From b5fbc92289ddf945d5f8340afdc459fc8efa870e Mon Sep 17 00:00:00 2001 From: Michael Forney Date: Sun, 30 Oct 2016 23:54:56 -0700 Subject: [PATCH 001/129] Port to wayland using wld --- Makefile | 12 +- config.def.h | 500 ++++++----- config.mk | 12 +- st.c | 2352 +++++++++++++++++++++++++------------------------- 4 files changed, 1449 insertions(+), 1427 deletions(-) diff --git a/Makefile b/Makefile index fb026c4..053d3e0 100644 --- a/Makefile +++ b/Makefile @@ -3,7 +3,7 @@ include config.mk -SRC = st.c +SRC = st.c xdg-shell-unstable-v5-protocol.c OBJ = ${SRC:.c=.o} all: options st @@ -17,6 +17,16 @@ options: config.h: cp config.def.h config.h +xdg-shell-unstable-v5-protocol.c: + @echo GEN $@ + @wayland-scanner code ${XDG_SHELL_PROTO} $@ + +xdg-shell-unstable-v5-client-protocol.h: + @echo GEN $@ + @wayland-scanner client-header ${XDG_SHELL_PROTO} $@ + +st.o: xdg-shell-unstable-v5-client-protocol.h + .c.o: @echo CC $< @${CC} -c ${CFLAGS} $< diff --git a/config.def.h b/config.def.h index 32d107d..41129e4 100644 --- a/config.def.h +++ b/config.def.h @@ -38,13 +38,13 @@ static char worddelimiters[] = " "; static unsigned int doubleclicktimeout = 300; static unsigned int tripleclicktimeout = 600; +/* key repeat timeouts (in milliseconds) */ +static unsigned int keyrepeatdelay = 500; +static unsigned int keyrepeatinterval = 25; + /* alt screens */ static int allowaltscreen = 1; -/* frames per second st should at maximum draw to the screen */ -static unsigned int xfps = 120; -static unsigned int actionfps = 30; - /* * blinking timeout (set to 0 to disable blinking) for the terminal blinking * attribute. @@ -60,7 +60,9 @@ 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; +/* XXX: Wayland does not have a bell. + * static int bellvolume = 0; + */ /* default TERM value */ static char termname[] = "st-256color"; @@ -131,11 +133,9 @@ static unsigned int defaultrcs = 257; static unsigned int cursorshape = 2; /* - * Default colour and shape of the mouse cursor + * Default shape of the mouse cursor */ -static unsigned int mouseshape = XC_xterm; -static unsigned int mousefg = 7; -static unsigned int mousebg = 0; +static char mouseshape[] = "xterm"; /* * Color used to display font attributes when fontconfig selected a font which @@ -149,36 +149,38 @@ static unsigned int defaultattr = 11; */ static MouseShortcut mshortcuts[] = { /* button mask string */ - { Button4, XK_ANY_MOD, "\031" }, - { Button5, XK_ANY_MOD, "\005" }, + { -1, MOD_MASK_NONE, "" } +}; + +static Axiskey ashortcuts[] = { + /* axis direction mask string */ + { AXIS_VERTICAL, +1, MOD_MASK_ANY, "\031"}, + { AXIS_VERTICAL, -1, MOD_MASK_ANY, "\005"}, }; /* Internal keyboard shortcuts. */ -#define MODKEY Mod1Mask +#define MODKEY MOD_MASK_ALT static Shortcut shortcuts[] = { - /* mask keysym function argument */ - { XK_ANY_MOD, XK_Break, sendbreak, {.i = 0} }, - { ControlMask, XK_Print, toggleprinter, {.i = 0} }, - { ShiftMask, XK_Print, printscreen, {.i = 0} }, - { XK_ANY_MOD, XK_Print, printsel, {.i = 0} }, - { MODKEY|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} }, + /* modifier key function argument */ + { MOD_MASK_ANY, XKB_KEY_Break, sendbreak, {.i = 0} }, + { MOD_MASK_CTRL, XKB_KEY_Print, toggleprinter, {.i = 0} }, + { MOD_MASK_SHIFT, XKB_KEY_Print, printscreen, {.i = 0} }, + { MOD_MASK_ANY, XKB_KEY_Print, printsel, {.i = 0} }, + { MODKEY|MOD_MASK_SHIFT, XKB_KEY_Prior, wlzoom, {.f = +1} }, + { MODKEY|MOD_MASK_SHIFT, XKB_KEY_Next, wlzoom, {.f = -1} }, + { MODKEY|MOD_MASK_SHIFT, XKB_KEY_Home, wlzoomreset, {.f = 0} }, + { MOD_MASK_SHIFT, XKB_KEY_Insert, selpaste, {.i = 0} }, + { MODKEY, XKB_KEY_Num_Lock, numlock, {.i = 0} }, + { MODKEY, XKB_KEY_Control_L, iso14755, {.i = 0} }, }; /* * Special keys (change & recompile st.info accordingly) * * Mask value: - * * Use XK_ANY_MOD to match the key no matter modifiers state - * * Use XK_NO_MOD to match the key alone (no modifiers) + * * Use MOD_MASK_ANY to match the key no matter modifiers state + * * Use MOD_MASK_NONE to match the key alone (no modifiers) * appkey value: * * 0: no value * * > 0: keypad application mode enabled @@ -194,7 +196,7 @@ static Shortcut shortcuts[] = { * * < 0: crlf mode is disabled * * Be careful with the order of the definitions because st searches in - * this table sequentially, so any XK_ANY_MOD must be in the last + * this table sequentially, so any MOD_MASK_ANY must be in the last * position for a key. */ @@ -202,239 +204,233 @@ static Shortcut shortcuts[] = { * If you want keys other than the X11 function keys (0xFD00 - 0xFFFF) * to be mapped below, add them to this array. */ -static KeySym mappedkeys[] = { -1 }; +static xkb_keysym_t mappedkeys[] = { -1 }; -/* - * 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; +/* State bits to ignore when matching key or button events. */ +static uint ignoremod = 0; /* * Override mouse-select while mask is active (when MODE_MOUSE is set). - * Note that if you want to use ShiftMask with selmasks, set this to an other - * modifier, set to 0 to not use it. + * Note that if you want to use MOD_MASK_SHIFT with selmasks, set this to an + * other modifier, set to 0 to not use it. */ -static uint forceselmod = ShiftMask; +static uint forceselmod = MOD_MASK_SHIFT; /* * This is the huge key array which defines all compatibility to the Linux * world. Please decide about changes wisely. */ static Key key[] = { - /* keysym mask string appkey appcursor 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 crlf */ + { XKB_KEY_KP_Home, MOD_MASK_SHIFT, "\033[2J", 0, -1, 0}, + { XKB_KEY_KP_Home, MOD_MASK_SHIFT, "\033[1;2H", 0, +1, 0}, + { XKB_KEY_KP_Home, MOD_MASK_ANY, "\033[H", 0, -1, 0}, + { XKB_KEY_KP_Home, MOD_MASK_ANY, "\033[1~", 0, +1, 0}, + { XKB_KEY_KP_Up, MOD_MASK_ANY, "\033Ox", +1, 0, 0}, + { XKB_KEY_KP_Up, MOD_MASK_ANY, "\033[A", 0, -1, 0}, + { XKB_KEY_KP_Up, MOD_MASK_ANY, "\033OA", 0, +1, 0}, + { XKB_KEY_KP_Down, MOD_MASK_ANY, "\033Or", +1, 0, 0}, + { XKB_KEY_KP_Down, MOD_MASK_ANY, "\033[B", 0, -1, 0}, + { XKB_KEY_KP_Down, MOD_MASK_ANY, "\033OB", 0, +1, 0}, + { XKB_KEY_KP_Left, MOD_MASK_ANY, "\033Ot", +1, 0, 0}, + { XKB_KEY_KP_Left, MOD_MASK_ANY, "\033[D", 0, -1, 0}, + { XKB_KEY_KP_Left, MOD_MASK_ANY, "\033OD", 0, +1, 0}, + { XKB_KEY_KP_Right, MOD_MASK_ANY, "\033Ov", +1, 0, 0}, + { XKB_KEY_KP_Right, MOD_MASK_ANY, "\033[C", 0, -1, 0}, + { XKB_KEY_KP_Right, MOD_MASK_ANY, "\033OC", 0, +1, 0}, + { XKB_KEY_KP_Prior, MOD_MASK_SHIFT, "\033[5;2~", 0, 0, 0}, + { XKB_KEY_KP_Prior, MOD_MASK_ANY, "\033[5~", 0, 0, 0}, + { XKB_KEY_KP_Begin, MOD_MASK_ANY, "\033[E", 0, 0, 0}, + { XKB_KEY_KP_End, MOD_MASK_CTRL, "\033[J", -1, 0, 0}, + { XKB_KEY_KP_End, MOD_MASK_CTRL, "\033[1;5F", +1, 0, 0}, + { XKB_KEY_KP_End, MOD_MASK_SHIFT, "\033[K", -1, 0, 0}, + { XKB_KEY_KP_End, MOD_MASK_SHIFT, "\033[1;2F", +1, 0, 0}, + { XKB_KEY_KP_End, MOD_MASK_ANY, "\033[4~", 0, 0, 0}, + { XKB_KEY_KP_Next, MOD_MASK_SHIFT, "\033[6;2~", 0, 0, 0}, + { XKB_KEY_KP_Next, MOD_MASK_ANY, "\033[6~", 0, 0, 0}, + { XKB_KEY_KP_Insert, MOD_MASK_SHIFT, "\033[2;2~", +1, 0, 0}, + { XKB_KEY_KP_Insert, MOD_MASK_SHIFT, "\033[4l", -1, 0, 0}, + { XKB_KEY_KP_Insert, MOD_MASK_CTRL, "\033[L", -1, 0, 0}, + { XKB_KEY_KP_Insert, MOD_MASK_CTRL, "\033[2;5~", +1, 0, 0}, + { XKB_KEY_KP_Insert, MOD_MASK_ANY, "\033[4h", -1, 0, 0}, + { XKB_KEY_KP_Insert, MOD_MASK_ANY, "\033[2~", +1, 0, 0}, + { XKB_KEY_KP_Delete, MOD_MASK_CTRL, "\033[M", -1, 0, 0}, + { XKB_KEY_KP_Delete, MOD_MASK_CTRL, "\033[3;5~", +1, 0, 0}, + { XKB_KEY_KP_Delete, MOD_MASK_SHIFT, "\033[2K", -1, 0, 0}, + { XKB_KEY_KP_Delete, MOD_MASK_SHIFT, "\033[3;2~", +1, 0, 0}, + { XKB_KEY_KP_Delete, MOD_MASK_ANY, "\033[P", -1, 0, 0}, + { XKB_KEY_KP_Delete, MOD_MASK_ANY, "\033[3~", +1, 0, 0}, + { XKB_KEY_KP_Multiply, MOD_MASK_ANY, "\033Oj", +2, 0, 0}, + { XKB_KEY_KP_Add, MOD_MASK_ANY, "\033Ok", +2, 0, 0}, + { XKB_KEY_KP_Enter, MOD_MASK_ANY, "\033OM", +2, 0, 0}, + { XKB_KEY_KP_Enter, MOD_MASK_ANY, "\r", -1, 0, -1}, + { XKB_KEY_KP_Enter, MOD_MASK_ANY, "\r\n", -1, 0, +1}, + { XKB_KEY_KP_Subtract, MOD_MASK_ANY, "\033Om", +2, 0, 0}, + { XKB_KEY_KP_Decimal, MOD_MASK_ANY, "\033On", +2, 0, 0}, + { XKB_KEY_KP_Divide, MOD_MASK_ANY, "\033Oo", +2, 0, 0}, + { XKB_KEY_KP_0, MOD_MASK_ANY, "\033Op", +2, 0, 0}, + { XKB_KEY_KP_1, MOD_MASK_ANY, "\033Oq", +2, 0, 0}, + { XKB_KEY_KP_2, MOD_MASK_ANY, "\033Or", +2, 0, 0}, + { XKB_KEY_KP_3, MOD_MASK_ANY, "\033Os", +2, 0, 0}, + { XKB_KEY_KP_4, MOD_MASK_ANY, "\033Ot", +2, 0, 0}, + { XKB_KEY_KP_5, MOD_MASK_ANY, "\033Ou", +2, 0, 0}, + { XKB_KEY_KP_6, MOD_MASK_ANY, "\033Ov", +2, 0, 0}, + { XKB_KEY_KP_7, MOD_MASK_ANY, "\033Ow", +2, 0, 0}, + { XKB_KEY_KP_8, MOD_MASK_ANY, "\033Ox", +2, 0, 0}, + { XKB_KEY_KP_9, MOD_MASK_ANY, "\033Oy", +2, 0, 0}, + { XKB_KEY_Up, MOD_MASK_SHIFT, "\033[1;2A", 0, 0, 0}, + { XKB_KEY_Up, MOD_MASK_ALT, "\033[1;3A", 0, 0, 0}, + { XKB_KEY_Up, MOD_MASK_SHIFT|MOD_MASK_ALT,"\033[1;4A", 0, 0, 0}, + { XKB_KEY_Up, MOD_MASK_CTRL, "\033[1;5A", 0, 0, 0}, + { XKB_KEY_Up,MOD_MASK_SHIFT|MOD_MASK_CTRL,"\033[1;6A", 0, 0, 0}, + { XKB_KEY_Up, MOD_MASK_CTRL|MOD_MASK_ALT,"\033[1;7A", 0, 0, 0}, + { XKB_KEY_Up,MOD_MASK_SHIFT|MOD_MASK_CTRL|MOD_MASK_ALT,"\033[1;8A",0,0,0}, + { XKB_KEY_Up, MOD_MASK_ANY, "\033[A", 0, -1, 0}, + { XKB_KEY_Up, MOD_MASK_ANY, "\033OA", 0, +1, 0}, + { XKB_KEY_Down, MOD_MASK_SHIFT, "\033[1;2B", 0, 0, 0}, + { XKB_KEY_Down, MOD_MASK_ALT, "\033[1;3B", 0, 0, 0}, + { XKB_KEY_Down,MOD_MASK_SHIFT|MOD_MASK_ALT,"\033[1;4B", 0, 0, 0}, + { XKB_KEY_Down, MOD_MASK_CTRL, "\033[1;5B", 0, 0, 0}, + { XKB_KEY_Down,MOD_MASK_SHIFT|MOD_MASK_CTRL,"\033[1;6B", 0, 0, 0}, + { XKB_KEY_Down,MOD_MASK_CTRL|MOD_MASK_ALT,"\033[1;7B", 0, 0, 0}, + { XKB_KEY_Down,MOD_MASK_SHIFT|MOD_MASK_CTRL|MOD_MASK_ALT,"\033[1;8B",0,0,0}, + { XKB_KEY_Down, MOD_MASK_ANY, "\033[B", 0, -1, 0}, + { XKB_KEY_Down, MOD_MASK_ANY, "\033OB", 0, +1, 0}, + { XKB_KEY_Left, MOD_MASK_SHIFT, "\033[1;2D", 0, 0, 0}, + { XKB_KEY_Left, MOD_MASK_ALT, "\033[1;3D", 0, 0, 0}, + { XKB_KEY_Left,MOD_MASK_SHIFT|MOD_MASK_ALT,"\033[1;4D", 0, 0, 0}, + { XKB_KEY_Left, MOD_MASK_CTRL, "\033[1;5D", 0, 0, 0}, + { XKB_KEY_Left,MOD_MASK_SHIFT|MOD_MASK_CTRL,"\033[1;6D", 0, 0, 0}, + { XKB_KEY_Left,MOD_MASK_CTRL|MOD_MASK_ALT,"\033[1;7D", 0, 0, 0}, + { XKB_KEY_Left,MOD_MASK_SHIFT|MOD_MASK_CTRL|MOD_MASK_ALT,"\033[1;8D",0,0,0}, + { XKB_KEY_Left, MOD_MASK_ANY, "\033[D", 0, -1, 0}, + { XKB_KEY_Left, MOD_MASK_ANY, "\033OD", 0, +1, 0}, + { XKB_KEY_Right, MOD_MASK_SHIFT, "\033[1;2C", 0, 0, 0}, + { XKB_KEY_Right, MOD_MASK_ALT, "\033[1;3C", 0, 0, 0}, + { XKB_KEY_Right,MOD_MASK_SHIFT|MOD_MASK_ALT,"\033[1;4C", 0, 0, 0}, + { XKB_KEY_Right, MOD_MASK_CTRL, "\033[1;5C", 0, 0, 0}, + { XKB_KEY_Right,MOD_MASK_SHIFT|MOD_MASK_CTRL,"\033[1;6C", 0, 0, 0}, + { XKB_KEY_Right,MOD_MASK_CTRL|MOD_MASK_ALT,"\033[1;7C", 0, 0, 0}, + { XKB_KEY_Right,MOD_MASK_SHIFT|MOD_MASK_CTRL|MOD_MASK_ALT,"\033[1;8C",0,0,0}, + { XKB_KEY_Right, MOD_MASK_ANY, "\033[C", 0, -1, 0}, + { XKB_KEY_Right, MOD_MASK_ANY, "\033OC", 0, +1, 0}, + { XKB_KEY_ISO_Left_Tab, MOD_MASK_SHIFT, "\033[Z", 0, 0, 0}, + { XKB_KEY_Return, MOD_MASK_ALT, "\033\r", 0, 0, -1}, + { XKB_KEY_Return, MOD_MASK_ALT, "\033\r\n", 0, 0, +1}, + { XKB_KEY_Return, MOD_MASK_ANY, "\r", 0, 0, -1}, + { XKB_KEY_Return, MOD_MASK_ANY, "\r\n", 0, 0, +1}, + { XKB_KEY_Insert, MOD_MASK_SHIFT, "\033[4l", -1, 0, 0}, + { XKB_KEY_Insert, MOD_MASK_SHIFT, "\033[2;2~", +1, 0, 0}, + { XKB_KEY_Insert, MOD_MASK_CTRL, "\033[L", -1, 0, 0}, + { XKB_KEY_Insert, MOD_MASK_CTRL, "\033[2;5~", +1, 0, 0}, + { XKB_KEY_Insert, MOD_MASK_ANY, "\033[4h", -1, 0, 0}, + { XKB_KEY_Insert, MOD_MASK_ANY, "\033[2~", +1, 0, 0}, + { XKB_KEY_Delete, MOD_MASK_CTRL, "\033[M", -1, 0, 0}, + { XKB_KEY_Delete, MOD_MASK_CTRL, "\033[3;5~", +1, 0, 0}, + { XKB_KEY_Delete, MOD_MASK_SHIFT, "\033[2K", -1, 0, 0}, + { XKB_KEY_Delete, MOD_MASK_SHIFT, "\033[3;2~", +1, 0, 0}, + { XKB_KEY_Delete, MOD_MASK_ANY, "\033[P", -1, 0, 0}, + { XKB_KEY_Delete, MOD_MASK_ANY, "\033[3~", +1, 0, 0}, + { XKB_KEY_BackSpace, MOD_MASK_NONE, "\177", 0, 0, 0}, + { XKB_KEY_BackSpace, MOD_MASK_CTRL, "\033\177", 0, 0, 0}, + { XKB_KEY_Home, MOD_MASK_SHIFT, "\033[2J", 0, -1, 0}, + { XKB_KEY_Home, MOD_MASK_SHIFT, "\033[1;2H", 0, +1, 0}, + { XKB_KEY_Home, MOD_MASK_ANY, "\033[H", 0, -1, 0}, + { XKB_KEY_Home, MOD_MASK_ANY, "\033[1~", 0, +1, 0}, + { XKB_KEY_End, MOD_MASK_CTRL, "\033[J", -1, 0, 0}, + { XKB_KEY_End, MOD_MASK_CTRL, "\033[1;5F", +1, 0, 0}, + { XKB_KEY_End, MOD_MASK_SHIFT, "\033[K", -1, 0, 0}, + { XKB_KEY_End, MOD_MASK_SHIFT, "\033[1;2F", +1, 0, 0}, + { XKB_KEY_End, MOD_MASK_ANY, "\033[4~", 0, 0, 0}, + { XKB_KEY_Prior, MOD_MASK_CTRL, "\033[5;5~", 0, 0, 0}, + { XKB_KEY_Prior, MOD_MASK_SHIFT, "\033[5;2~", 0, 0, 0}, + { XKB_KEY_Prior, MOD_MASK_ANY, "\033[5~", 0, 0, 0}, + { XKB_KEY_Next, MOD_MASK_CTRL, "\033[6;5~", 0, 0, 0}, + { XKB_KEY_Next, MOD_MASK_SHIFT, "\033[6;2~", 0, 0, 0}, + { XKB_KEY_Next, MOD_MASK_ANY, "\033[6~", 0, 0, 0}, + { XKB_KEY_F1, MOD_MASK_NONE, "\033OP" , 0, 0, 0}, + { XKB_KEY_F1, /* F13 */ MOD_MASK_SHIFT, "\033[1;2P", 0, 0, 0}, + { XKB_KEY_F1, /* F25 */ MOD_MASK_CTRL, "\033[1;5P", 0, 0, 0}, + { XKB_KEY_F1, /* F37 */ MOD_MASK_LOGO, "\033[1;6P", 0, 0, 0}, + { XKB_KEY_F1, /* F49 */ MOD_MASK_ALT, "\033[1;3P", 0, 0, 0}, + { XKB_KEY_F2, MOD_MASK_NONE, "\033OQ" , 0, 0, 0}, + { XKB_KEY_F2, /* F14 */ MOD_MASK_SHIFT, "\033[1;2Q", 0, 0, 0}, + { XKB_KEY_F2, /* F26 */ MOD_MASK_CTRL, "\033[1;5Q", 0, 0, 0}, + { XKB_KEY_F2, /* F38 */ MOD_MASK_LOGO, "\033[1;6Q", 0, 0, 0}, + { XKB_KEY_F2, /* F50 */ MOD_MASK_ALT, "\033[1;3Q", 0, 0, 0}, + { XKB_KEY_F3, MOD_MASK_NONE, "\033OR" , 0, 0, 0}, + { XKB_KEY_F3, /* F15 */ MOD_MASK_SHIFT, "\033[1;2R", 0, 0, 0}, + { XKB_KEY_F3, /* F27 */ MOD_MASK_CTRL, "\033[1;5R", 0, 0, 0}, + { XKB_KEY_F3, /* F39 */ MOD_MASK_LOGO, "\033[1;6R", 0, 0, 0}, + { XKB_KEY_F3, /* F51 */ MOD_MASK_ALT, "\033[1;3R", 0, 0, 0}, + { XKB_KEY_F4, MOD_MASK_NONE, "\033OS" , 0, 0, 0}, + { XKB_KEY_F4, /* F16 */ MOD_MASK_SHIFT, "\033[1;2S", 0, 0, 0}, + { XKB_KEY_F4, /* F28 */ MOD_MASK_CTRL, "\033[1;5S", 0, 0, 0}, + { XKB_KEY_F4, /* F40 */ MOD_MASK_LOGO, "\033[1;6S", 0, 0, 0}, + { XKB_KEY_F4, /* F52 */ MOD_MASK_ALT, "\033[1;3S", 0, 0, 0}, + { XKB_KEY_F5, MOD_MASK_NONE, "\033[15~", 0, 0, 0}, + { XKB_KEY_F5, /* F17 */ MOD_MASK_SHIFT, "\033[15;2~", 0, 0, 0}, + { XKB_KEY_F5, /* F29 */ MOD_MASK_CTRL, "\033[15;5~", 0, 0, 0}, + { XKB_KEY_F5, /* F41 */ MOD_MASK_LOGO, "\033[15;6~", 0, 0, 0}, + { XKB_KEY_F5, /* F53 */ MOD_MASK_ALT, "\033[15;3~", 0, 0, 0}, + { XKB_KEY_F6, MOD_MASK_NONE, "\033[17~", 0, 0, 0}, + { XKB_KEY_F6, /* F18 */ MOD_MASK_SHIFT, "\033[17;2~", 0, 0, 0}, + { XKB_KEY_F6, /* F30 */ MOD_MASK_CTRL, "\033[17;5~", 0, 0, 0}, + { XKB_KEY_F6, /* F42 */ MOD_MASK_LOGO, "\033[17;6~", 0, 0, 0}, + { XKB_KEY_F6, /* F54 */ MOD_MASK_ALT, "\033[17;3~", 0, 0, 0}, + { XKB_KEY_F7, MOD_MASK_NONE, "\033[18~", 0, 0, 0}, + { XKB_KEY_F7, /* F19 */ MOD_MASK_SHIFT, "\033[18;2~", 0, 0, 0}, + { XKB_KEY_F7, /* F31 */ MOD_MASK_CTRL, "\033[18;5~", 0, 0, 0}, + { XKB_KEY_F7, /* F43 */ MOD_MASK_LOGO, "\033[18;6~", 0, 0, 0}, + { XKB_KEY_F7, /* F55 */ MOD_MASK_ALT, "\033[18;3~", 0, 0, 0}, + { XKB_KEY_F8, MOD_MASK_NONE, "\033[19~", 0, 0, 0}, + { XKB_KEY_F8, /* F20 */ MOD_MASK_SHIFT, "\033[19;2~", 0, 0, 0}, + { XKB_KEY_F8, /* F32 */ MOD_MASK_CTRL, "\033[19;5~", 0, 0, 0}, + { XKB_KEY_F8, /* F44 */ MOD_MASK_LOGO, "\033[19;6~", 0, 0, 0}, + { XKB_KEY_F8, /* F56 */ MOD_MASK_ALT, "\033[19;3~", 0, 0, 0}, + { XKB_KEY_F9, MOD_MASK_NONE, "\033[20~", 0, 0, 0}, + { XKB_KEY_F9, /* F21 */ MOD_MASK_SHIFT, "\033[20;2~", 0, 0, 0}, + { XKB_KEY_F9, /* F33 */ MOD_MASK_CTRL, "\033[20;5~", 0, 0, 0}, + { XKB_KEY_F9, /* F45 */ MOD_MASK_LOGO, "\033[20;6~", 0, 0, 0}, + { XKB_KEY_F9, /* F57 */ MOD_MASK_ALT, "\033[20;3~", 0, 0, 0}, + { XKB_KEY_F10, MOD_MASK_NONE, "\033[21~", 0, 0, 0}, + { XKB_KEY_F10, /* F22 */ MOD_MASK_SHIFT, "\033[21;2~", 0, 0, 0}, + { XKB_KEY_F10, /* F34 */ MOD_MASK_CTRL, "\033[21;5~", 0, 0, 0}, + { XKB_KEY_F10, /* F46 */ MOD_MASK_LOGO, "\033[21;6~", 0, 0, 0}, + { XKB_KEY_F10, /* F58 */ MOD_MASK_ALT, "\033[21;3~", 0, 0, 0}, + { XKB_KEY_F11, MOD_MASK_NONE, "\033[23~", 0, 0, 0}, + { XKB_KEY_F11, /* F23 */ MOD_MASK_SHIFT, "\033[23;2~", 0, 0, 0}, + { XKB_KEY_F11, /* F35 */ MOD_MASK_CTRL, "\033[23;5~", 0, 0, 0}, + { XKB_KEY_F11, /* F47 */ MOD_MASK_LOGO, "\033[23;6~", 0, 0, 0}, + { XKB_KEY_F11, /* F59 */ MOD_MASK_ALT, "\033[23;3~", 0, 0, 0}, + { XKB_KEY_F12, MOD_MASK_NONE, "\033[24~", 0, 0, 0}, + { XKB_KEY_F12, /* F24 */ MOD_MASK_SHIFT, "\033[24;2~", 0, 0, 0}, + { XKB_KEY_F12, /* F36 */ MOD_MASK_CTRL, "\033[24;5~", 0, 0, 0}, + { XKB_KEY_F12, /* F48 */ MOD_MASK_LOGO, "\033[24;6~", 0, 0, 0}, + { XKB_KEY_F12, /* F60 */ MOD_MASK_ALT, "\033[24;3~", 0, 0, 0}, + { XKB_KEY_F13, MOD_MASK_NONE, "\033[1;2P", 0, 0, 0}, + { XKB_KEY_F14, MOD_MASK_NONE, "\033[1;2Q", 0, 0, 0}, + { XKB_KEY_F15, MOD_MASK_NONE, "\033[1;2R", 0, 0, 0}, + { XKB_KEY_F16, MOD_MASK_NONE, "\033[1;2S", 0, 0, 0}, + { XKB_KEY_F17, MOD_MASK_NONE, "\033[15;2~", 0, 0, 0}, + { XKB_KEY_F18, MOD_MASK_NONE, "\033[17;2~", 0, 0, 0}, + { XKB_KEY_F19, MOD_MASK_NONE, "\033[18;2~", 0, 0, 0}, + { XKB_KEY_F20, MOD_MASK_NONE, "\033[19;2~", 0, 0, 0}, + { XKB_KEY_F21, MOD_MASK_NONE, "\033[20;2~", 0, 0, 0}, + { XKB_KEY_F22, MOD_MASK_NONE, "\033[21;2~", 0, 0, 0}, + { XKB_KEY_F23, MOD_MASK_NONE, "\033[23;2~", 0, 0, 0}, + { XKB_KEY_F24, MOD_MASK_NONE, "\033[24;2~", 0, 0, 0}, + { XKB_KEY_F25, MOD_MASK_NONE, "\033[1;5P", 0, 0, 0}, + { XKB_KEY_F26, MOD_MASK_NONE, "\033[1;5Q", 0, 0, 0}, + { XKB_KEY_F27, MOD_MASK_NONE, "\033[1;5R", 0, 0, 0}, + { XKB_KEY_F28, MOD_MASK_NONE, "\033[1;5S", 0, 0, 0}, + { XKB_KEY_F29, MOD_MASK_NONE, "\033[15;5~", 0, 0, 0}, + { XKB_KEY_F30, MOD_MASK_NONE, "\033[17;5~", 0, 0, 0}, + { XKB_KEY_F31, MOD_MASK_NONE, "\033[18;5~", 0, 0, 0}, + { XKB_KEY_F32, MOD_MASK_NONE, "\033[19;5~", 0, 0, 0}, + { XKB_KEY_F33, MOD_MASK_NONE, "\033[20;5~", 0, 0, 0}, + { XKB_KEY_F34, MOD_MASK_NONE, "\033[21;5~", 0, 0, 0}, + { XKB_KEY_F35, MOD_MASK_NONE, "\033[23;5~", 0, 0, 0}, }; /* @@ -445,7 +441,7 @@ static Key key[] = { * If no match is found, regular selection is used. */ static uint selmasks[] = { - [SEL_RECTANGULAR] = Mod1Mask, + [SEL_RECTANGULAR] = MOD_MASK_ALT, }; /* diff --git a/config.mk b/config.mk index c84c5ee..7da06f1 100644 --- a/config.mk +++ b/config.mk @@ -7,16 +7,12 @@ VERSION = 0.7 PREFIX = /usr/local MANPREFIX = ${PREFIX}/share/man -X11INC = /usr/X11R6/include -X11LIB = /usr/X11R6/lib +PKGCFG = fontconfig wayland-client wayland-cursor xkbcommon wld +XDG_SHELL_PROTO = `pkg-config --variable=pkgdatadir wayland-protocols`/unstable/xdg-shell/xdg-shell-unstable-v5.xml # includes and libs -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 \ - `pkg-config --libs fontconfig` \ - `pkg-config --libs freetype2` +INCS = -I. -I/usr/include `pkg-config --cflags ${PKGCFG}` +LIBS = -L/usr/lib -lc -lm -lrt -lutil `pkg-config --libs ${PKGCFG}` # flags CPPFLAGS = -DVERSION=\"${VERSION}\" -D_XOPEN_SOURCE=600 diff --git a/st.c b/st.c index e50e884..b891b07 100644 --- a/st.c +++ b/st.c @@ -3,6 +3,8 @@ #include #include #include +/* for BTN_* definitions */ +#include #include #include #include @@ -12,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -21,23 +24,19 @@ #include #include #include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include #include #include #include "arg.h" +#include "xdg-shell-unstable-v5-client-protocol.h" char *argv0; -#define Glyph Glyph_ -#define Font Font_ - #if defined(__linux) #include #elif defined(__OpenBSD__) || defined(__NetBSD__) || defined(__APPLE__) @@ -47,10 +46,6 @@ char *argv0; #endif -/* XEMBED messages */ -#define XEMBED_FOCUS_IN 4 -#define XEMBED_FOCUS_OUT 5 - /* Arbitrary sizes */ #define UTF_INVALID 0xFFFD #define UTF_SIZ 4 @@ -58,15 +53,25 @@ char *argv0; #define ESC_ARG_SIZ 16 #define STR_BUF_SIZ ESC_BUF_SIZ #define STR_ARG_SIZ ESC_ARG_SIZ +#define DRAW_BUF_SIZ 20*1024 #define XK_ANY_MOD UINT_MAX #define XK_NO_MOD 0 #define XK_SWITCH_MOD (1<<13) +#define MOD_MASK_ANY UINT_MAX +#define MOD_MASK_NONE 0 +#define MOD_MASK_CTRL (1<<0) +#define MOD_MASK_ALT (1<<1) +#define MOD_MASK_SHIFT (1<<2) +#define MOD_MASK_LOGO (1<<3) + +#define AXIS_VERTICAL WL_POINTER_AXIS_VERTICAL_SCROLL +#define AXIS_HORIZONTAL WL_POINTER_AXIS_HORIZONTAL_SCROLL + /* 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 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)) @@ -89,7 +94,7 @@ char *argv0; #define TRUEBLUE(x) (((x) & 0xff) << 8) /* constants */ -#define ISO14755CMD "dmenu -w %lu -p codepoint: xbutton.state & ~(Button1Mask | forceselmod); + uint state = wl.xkb.mods & ~forceselmod; sel.alt = IS_SET(MODE_ALTSCREEN); - sel.oe.x = x2col(e->xbutton.x); - sel.oe.y = y2row(e->xbutton.y); + sel.oe.x = x2col(wl.px); + sel.oe.y = y2row(wl.py); selnormalize(); sel.type = SEL_REGULAR; @@ -889,59 +942,20 @@ getbuttoninfo(XEvent *e) } void -mousereport(XEvent *e) +wlmousereport(int button, bool release, int x, int y) { - int x = x2col(e->xbutton.x), y = y2row(e->xbutton.y), - button = e->xbutton.button, state = e->xbutton.state, - len; + int 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); + button += ((wl.xkb.mods & MOD_MASK_SHIFT) ? 4 : 0) + + ((wl.xkb.mods & MOD_MASK_LOGO ) ? 8 : 0) + + ((wl.xkb.mods & MOD_MASK_CTRL ) ? 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'); + button, x+1, y+1, release ? '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); @@ -953,53 +967,59 @@ mousereport(XEvent *e) } void -bpress(XEvent *e) +wlmousereportbutton(uint32_t button, uint32_t state) { - struct timespec now; - MouseShortcut *ms; + bool release = state == WL_POINTER_BUTTON_STATE_RELEASED; - if (IS_SET(MODE_MOUSE) && !(e->xbutton.state & forceselmod)) { - mousereport(e); - return; + if (!IS_SET(MODE_MOUSESGR) && release) { + button = 3; + } else { + switch (button) { + case BTN_LEFT: + button = 0; + break; + case BTN_MIDDLE: + button = 1; + break; + case BTN_RIGHT: + button = 2; + break; + } } - 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; - } + oldbutton = release ? 3 : button; + + /* don't report release events when in X10 mode */ + if (IS_SET(MODE_MOUSEX10) && release) { + return; } - if (e->xbutton.button == Button1) { - clock_gettime(CLOCK_MONOTONIC, &now); + wlmousereport(button, release, oldx, oldy); +} - /* 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); +void +wlmousereportmotion(wl_fixed_t fx, wl_fixed_t fy) +{ + int x = x2col(wl_fixed_to_int(fx)), y = y2row(wl_fixed_to_int(fy)); - /* - * 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 (x == oldx && y == oldy) + 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; - if (sel.snap != 0) - sel.mode = SEL_READY; - tsetdirt(sel.nb.y, sel.ne.y); - sel.tclick2 = sel.tclick1; - sel.tclick1 = now; - } + oldx = x; + oldy = y; + wlmousereport(oldbutton + 32, false, x, y); +} + +void +wlmousereportaxis(uint32_t axis, wl_fixed_t amount) +{ + wlmousereport(64 + (axis == AXIS_VERTICAL ? 4 : 6) + + (amount > 0 ? 1 : 0), false, oldx, oldy); } char * @@ -1057,148 +1077,67 @@ getsel(void) } void -selcopy(Time t) -{ - xsetsel(getsel(), t); -} - -void -propnotify(XEvent *e) +selcopy(uint32_t serial) { - 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); - } + wlsetsel(getsel(), serial); } -void -selnotify(XEvent *e) +static inline void +selwritebuf(char *buf, int len) { - 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); + char *repl = buf; /* - * Deleting the property again tells the selection owner to send the - * next data chunk in the property. + * 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. */ - XDeleteProperty(xw.dpy, xw.win, (int)property); -} + while ((repl = memchr(repl, '\n', len))) { + *repl++ = '\r'; + } -void -selpaste(const Arg *dummy) -{ - XConvertSelection(xw.dpy, XA_PRIMARY, sel.xtarget, XA_PRIMARY, - xw.win, CurrentTime); + ttysend(buf, len); } void -clipcopy(const Arg *dummy) +selpaste(const Arg *dummy) { - Atom clipboard; + int fds[2], len, left; + char buf[BUFSIZ], *str; - 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); + if (wl.seloffer) { + if (IS_SET(MODE_BRCKTPASTE)) + ttywrite("\033[200~", 6); + /* check if we are pasting from ourselves */ + if (sel.source) { + str = sel.primary; + left = strlen(sel.primary); + while (left > 0) { + len = MIN(sizeof buf, left); + memcpy(buf, str, len); + selwritebuf(buf, len); + left -= len; + str += len; + } + } else { + pipe(fds); + wl_data_offer_receive(wl.seloffer, "text/plain", fds[1]); + wl_display_flush(wl.dpy); + close(fds[1]); + while ((len = read(fds[0], buf, sizeof buf)) > 0) { + selwritebuf(buf, len); + } + close(fds[0]); + } + if (IS_SET(MODE_BRCKTPASTE)) + ttywrite("\033[201~", 6); } } 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; @@ -1208,117 +1147,19 @@ 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) +wlsetsel(char *str, uint32_t serial) { free(sel.primary); sel.primary = str; - XSetSelectionOwner(xw.dpy, XA_PRIMARY, xw.win, t); - if (XGetSelectionOwner(xw.dpy, XA_PRIMARY) != xw.win) - selclear(0); -} - -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 (str) { + sel.source = wl_data_device_manager_create_data_source(wl.datadevmanager); + wl_data_source_add_listener(sel.source, &datasrclistener, NULL); + wl_data_source_offer(sel.source, "text/plain; charset=utf-8"); + } else { + sel.source = NULL; } - - 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)); + wl_data_device_set_selection(wl.datadev, sel.source, serial); } void @@ -1337,7 +1178,6 @@ execsh(void) { char **args, *sh, *prog; const struct passwd *pw; - char buf[sizeof(long) * 8 + 1]; errno = 0; if ((pw = getpwuid(getuid())) == NULL) { @@ -1358,8 +1198,6 @@ execsh(void) prog = sh; args = (opt_cmd) ? opt_cmd : (char *[]) {prog, NULL}; - snprintf(buf, sizeof(buf), "%lu", xw.win); - unsetenv("COLUMNS"); unsetenv("LINES"); unsetenv("TERMCAP"); @@ -1368,7 +1206,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); @@ -1513,6 +1350,7 @@ ttyread(void) if (buflen > 0) memmove(buf, ptr, buflen); + needdraw = true; return ret; } @@ -1606,8 +1444,8 @@ ttyresize(void) w.ws_row = term.row; w.ws_col = term.col; - w.ws_xpixel = xw.tw; - w.ws_ypixel = xw.th; + w.ws_xpixel = wl.tw; + w.ws_ypixel = wl.th; if (ioctl(cmdfd, TIOCSWINSZ, &w) < 0) fprintf(stderr, "Couldn't set window size: %s\n", strerror(errno)); } @@ -1637,6 +1475,8 @@ tsetdirt(int top, int bot) for (i = top; i <= bot; i++) term.dirty[i] = 1; + + needdraw = true; } void @@ -1771,7 +1611,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) { @@ -1917,7 +1757,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; @@ -2180,22 +2020,18 @@ tsetmode(int priv, int set, int *args, int narg) MODBIT(term.mode, !set, MODE_HIDE); break; case 9: /* X10 mouse compatibility mode */ - xsetpointermotion(0); MODBIT(term.mode, 0, MODE_MOUSE); MODBIT(term.mode, set, MODE_MOUSEX10); break; case 1000: /* 1000: report button press */ - xsetpointermotion(0); MODBIT(term.mode, 0, MODE_MOUSE); MODBIT(term.mode, 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); break; case 1003: /* 1003: enable all mouse motions */ - xsetpointermotion(set); MODBIT(term.mode, 0, MODE_MOUSE); MODBIT(term.mode, set, MODE_MOUSEMANY); break; @@ -2368,7 +2204,7 @@ csihandle(void) tputtab(csiescseq.arg[0]); break; case 'J': /* ED -- Clear screen */ - selclear(NULL); + selclear(); switch (csiescseq.arg[0]) { case 0: /* below */ tclearregion(term.c.x, term.c.y, term.col-1, term.c.y); @@ -2475,7 +2311,7 @@ csihandle(void) if (!BETWEEN(csiescseq.arg[0], 0, 6)) { goto unknown; } - xw.cursor = csiescseq.arg[0]; + wl.cursor = csiescseq.arg[0]; break; default: goto unknown; @@ -2531,7 +2367,7 @@ strhandle(void) case 1: case 2: if (narg > 1) - xsettitle(strescseq.args[1]); + wlsettitle(strescseq.args[1]); return; case 4: /* color set */ if (narg < 3) @@ -2540,7 +2376,7 @@ strhandle(void) /* FALLTHROUGH */ case 104: /* color reset, here p = NULL */ j = (narg > 1) ? atoi(strescseq.args[1]) : -1; - if (xsetcolorname(j, p)) { + if (wlsetcolorname(j, p)) { fprintf(stderr, "erresc: invalid color %s\n", p); } else { /* @@ -2553,7 +2389,7 @@ strhandle(void) } break; case 'k': /* old title set compatibility */ - xsettitle(strescseq.args[0]); + wlsettitle(strescseq.args[0]); return; case 'P': /* DCS -- Device Control String */ term.mode |= ESC_DCS; @@ -2642,13 +2478,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,6 +2581,7 @@ techo(Rune u) } } tputc(u); + needdraw = true; } void @@ -2833,10 +2668,12 @@ 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); + if (!(wl.state & WIN_FOCUSED)) + wlseturgency(1); + /* XXX: No bell on wayland + * if (bellvolume) + * XkbBell(xw.dpy, xw.win, bellvolume, (Atom)NULL); + */ } break; case '\033': /* ESC */ @@ -2968,8 +2805,8 @@ eschandle(uchar ascii) break; case 'c': /* RIS -- Reset to inital state */ treset(); - xresettitle(); - xloadcols(); + wlresettitle(); + wlloadcols(); break; case '=': /* DECPAM -- Application keypad */ term.mode |= MODE_APPKEYPAD; @@ -3026,7 +2863,7 @@ tputc(Rune u) */ if (term.esc & ESC_STR) { if (u == '\a' || u == 030 || u == 032 || u == 033 || - ISCONTROLC1(u)) { + ISCONTROLC1(u)) { term.esc &= ~(ESC_START|ESC_STR|ESC_DCS); if (IS_SET(MODE_SIXEL)) { /* TODO: render sixel */; @@ -3109,7 +2946,7 @@ tputc(Rune u) 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)) { @@ -3176,9 +3013,6 @@ 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)); @@ -3228,190 +3062,141 @@ tresize(int col, int row) } void -xresize(int col, int row) +wlresize(int col, int row) { - xw.tw = MAX(1, col * xw.cw); - xw.th = MAX(1, row * xw.ch); + union wld_object object; + + wl.tw = MAX(1, col * wl.cw); + wl.th = MAX(1, row * wl.ch); - XFreePixmap(xw.dpy, xw.buf); - xw.buf = XCreatePixmap(xw.dpy, xw.win, xw.w, xw.h, - DefaultDepth(xw.dpy, xw.scr)); - XftDrawChange(xw.draw, xw.buf); - xclear(0, 0, xw.w, xw.h); + wld.oldbuffer = wld.buffer; + wld.buffer = wld_create_buffer(wld.ctx, wl.w, wl.h, + WLD_FORMAT_XRGB8888, 0); + wld_export(wld.buffer, WLD_WAYLAND_OBJECT_BUFFER, &object); + wl.buffer = object.ptr; } -ushort -sixd_to_16bit(int x) +uchar +sixd_to_8bit(int x) { - return x == 0 ? 0 : 0x3737 + 0x2828 * x; + return x == 0 ? 0 : 0x37 + 0x28 * x; } int -xloadcolor(int i, const char *name, Color *ncolor) +wlloadcolor(int i, const char *name, uint32_t *color) { - 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 ); + *color = 0xff << 24 | sixd_to_8bit(((i-16)/36)%6) << 16 + | sixd_to_8bit(((i-16)/6)%6) << 8 + | sixd_to_8bit(((i-16)/1)%6); } else { /* greyscale */ - color.red = 0x0808 + 0x0a0a * (i - (6*6*6+16)); - color.green = color.blue = color.red; + *color = 0xff << 24 | (0x8 + 0xa * (i-(6*6*6+16))) * 0x10101; } - return XftColorAllocValue(xw.dpy, xw.vis, - xw.cmap, &color, ncolor); + return true; } else name = colorname[i]; } - return XftColorAllocName(xw.dpy, xw.vis, xw.cmap, name, ncolor); + return wld_lookup_named_color(name, color); } void -xloadcols(void) +wlloadcols(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 (!wlloadcolor(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); } - loaded = 1; } int -xsetcolorname(int x, const char *name) +wlsetcolorname(int x, const char *name) { - Color ncolor; + uint32_t color; if (!BETWEEN(x, 0, LEN(dc.col))) return 1; - - if (!xloadcolor(x, name, &ncolor)) + if (!wlloadcolor(x, name, &color)) return 1; - XftColorFree(xw.dpy, xw.vis, xw.cmap, &dc.col[x]); - dc.col[x] = ncolor; + dc.col[x] = color; return 0; } -/* - * Absolute coordinates. - */ -void -xclear(int x1, int y1, int x2, int y2) +static void wlloadcursor(void) { - XftDrawRect(xw.draw, - &dc.col[IS_SET(MODE_REVERSE)? defaultfg : defaultbg], - x1, y1, x2-x1, y2-y1); -} + char *names[] = { mouseshape, "xterm", "ibeam", "text" }; + int i; -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); - } + cursor.theme = wl_cursor_theme_load(NULL, 32, wl.shm); + + for (i = 0; !cursor.cursor && i < LEN(names); i++) + cursor.cursor = wl_cursor_theme_get_cursor(cursor.theme, names[i]); - XSetWMProperties(xw.dpy, xw.win, NULL, NULL, NULL, 0, sizeh, &wm, - &class); - XFree(sizeh); + cursor.surface = wl_compositor_create_surface(wl.cmp); } -int -xgeommasktogravity(int mask) +/* + * Absolute coordinates. + */ +void +wlclear(int x1, int y1, int x2, int y2) { - switch (mask & (XNegative|YNegative)) { - case 0: - return NorthWestGravity; - case XNegative: - return NorthEastGravity; - case YNegative: - return SouthWestGravity; - } + uint32_t color = dc.col[IS_SET(MODE_REVERSE) ? defaultfg : defaultbg]; - return SouthEastGravity; + wld_fill_rectangle(wld.renderer, color, x1, y1, x2 - x1, y2 - y1); } int -xloadfont(Font *f, FcPattern *pattern) +wlloadfont(Font *f, FcPattern *pattern) { FcPattern *match; FcResult result; - XGlyphInfo extents; + struct wld_extents extents; int wantattr, haveattr; - match = XftFontMatch(xw.dpy, xw.scr, pattern, &result); + match = FcFontMatch(NULL, pattern, &result); if (!match) return 1; - if (!(f->match = XftFontOpenPattern(xw.dpy, match))) { + if (!(f->match = wld_font_open_pattern(wld.fontctx, match))) { FcPatternDestroy(match); return 1; } - if ((XftPatternGetInteger(pattern, "slant", 0, &wantattr) == - XftResultMatch)) { + if ((FcPatternGetInteger(pattern, "slant", 0, &wantattr) == + FcResultMatch)) { /* * 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) { + if ((FcPatternGetInteger(match, "slant", 0, + &haveattr) != FcResultMatch) || 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) { + if ((FcPatternGetInteger(pattern, "weight", 0, &wantattr) == + FcResultMatch)) { + if ((FcPatternGetInteger(match, "weight", 0, + &haveattr) != FcResultMatch) || 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); + + wld_font_text_extents(f->match, ascii_printable, &extents); f->set = NULL; f->pattern = FcPatternDuplicate(pattern); @@ -3419,23 +3204,24 @@ xloadfont(Font *f, FcPattern *pattern) f->ascent = f->match->ascent; f->descent = f->match->descent; f->lbearing = 0; - f->rbearing = f->match->max_advance_width; + f->rbearing = f->match->max_advance; f->height = f->ascent + f->descent; - f->width = DIVCEIL(extents.xOff, strlen(ascii_printable)); + f->width = DIVCEIL(extents.advance, strlen(ascii_printable)); return 0; } void -xloadfonts(char *fontstr, double fontsize) +wlloadfonts(char *fontstr, double fontsize) { FcPattern *pattern; double fontval; float ceilf(float); if (fontstr[0] == '-') { - pattern = XftXlfdParse(fontstr, False, False); + /* XXX: need XftXlfdParse equivalent */ + pattern = NULL; } else { pattern = FcNameParse((FcChar8 *)fontstr); } @@ -3466,14 +3252,17 @@ xloadfonts(char *fontstr, double fontsize) defaultfontsize = usedfontsize; } - if (xloadfont(&dc.font, pattern)) + FcConfigSubstitute(0, pattern, FcMatchPattern); + FcDefaultSubstitute(pattern); + + if (wlloadfont(&dc.font, pattern)) die("st: can't open font %s\n", fontstr); if (usedfontsize < 0) { - FcPatternGetDouble(dc.font.match->pattern, + FcPatternGetDouble(dc.font.pattern, FC_PIXEL_SIZE, 0, &fontval); FcPatternAddDouble(pattern, FC_PIXEL_SIZE, fontval); - if (xloadfont(&dc.font, pattern)) + if (wlloadfont(&dc.font, pattern)) die("st: can't open font %s\n", fontstr); usedfontsize = fontval; if (fontsize == 0) @@ -3481,279 +3270,331 @@ xloadfonts(char *fontstr, double fontsize) } /* Setting character width and height. */ - xw.cw = ceilf(dc.font.width * cwscale); - xw.ch = ceilf(dc.font.height * chscale); + wl.cw = ceilf(dc.font.width * cwscale); + wl.ch = ceilf(dc.font.height * chscale); FcPatternDel(pattern, FC_SLANT); FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ITALIC); - if (xloadfont(&dc.ifont, pattern)) + if (wlloadfont(&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)) + if (wlloadfont(&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)) + if (wlloadfont(&dc.bfont, pattern)) die("st: can't open font %s\n", fontstr); FcPatternDestroy(pattern); } void -xunloadfont(Font *f) +wlunloadfont(Font *f) { - XftFontClose(xw.dpy, f->match); + wld_font_close(f->match); FcPatternDestroy(f->pattern); if (f->set) FcFontSetDestroy(f->set); } void -xunloadfonts(void) +wlunloadfonts(void) { /* Free the loaded fonts in the font cache. */ while (frclen > 0) - XftFontClose(xw.dpy, frc[--frclen].font); + wld_font_close(frc[--frclen].font); - xunloadfont(&dc.font); - xunloadfont(&dc.bfont); - xunloadfont(&dc.ifont); - xunloadfont(&dc.ibfont); + wlunloadfont(&dc.font); + wlunloadfont(&dc.bfont); + wlunloadfont(&dc.ifont); + wlunloadfont(&dc.ibfont); } void -xzoom(const Arg *arg) +wlzoom(const Arg *arg) { Arg larg; larg.f = usedfontsize + arg->f; - xzoomabs(&larg); + wlzoomabs(&larg); } void -xzoomabs(const Arg *arg) +wlzoomabs(const Arg *arg) { - xunloadfonts(); - xloadfonts(usedfont, arg->f); + wlunloadfonts(); + wlloadfonts(usedfont, arg->f); cresize(0, 0); ttyresize(); redraw(); - xhints(); + /* XXX: Should the window size be updated here because wayland doesn't + * have a notion of hints? + * xhints(); + */ } void -xzoomreset(const Arg *arg) +wlzoomreset(const Arg *arg) { Arg larg; if (defaultfontsize > 0) { larg.f = defaultfontsize; - xzoomabs(&larg); + wlzoomabs(&larg); } } void -xinit(void) +wlinit(void) { - XGCValues gcvalues; - Cursor cursor; - Window parent; - pid_t thispid = getpid(); - XColor xmousefg, xmousebg; + struct wl_registry *registry; - if (!(xw.dpy = XOpenDisplay(NULL))) + if (!(wl.dpy = wl_display_connect(NULL))) die("Can't open display\n"); - xw.scr = XDefaultScreen(xw.dpy); - xw.vis = XDefaultVisual(xw.dpy, xw.scr); + + registry = wl_display_get_registry(wl.dpy); + wl_registry_add_listener(registry, ®listener, NULL); + wld.ctx = wld_wayland_create_context(wl.dpy, WLD_ANY); + wld.renderer = wld_create_renderer(wld.ctx); + + wl_display_roundtrip(wl.dpy); + + if (!wl.shm) + die("Display has no SHM\n"); + if (!wl.seat) + die("Display has no seat\n"); + if (!wl.datadevmanager) + die("Display has no data device manager\n"); + + wl.keyboard = wl_seat_get_keyboard(wl.seat); + wl_keyboard_add_listener(wl.keyboard, &kbdlistener, NULL); + wl.pointer = wl_seat_get_pointer(wl.seat); + wl_pointer_add_listener(wl.pointer, &ptrlistener, NULL); + wl.datadev = wl_data_device_manager_get_data_device(wl.datadevmanager, + wl.seat); + wl_data_device_add_listener(wl.datadev, &datadevlistener, NULL); /* font */ if (!FcInit()) die("Could not init fontconfig.\n"); usedfont = (opt_font == NULL)? font : opt_font; - xloadfonts(usedfont, 0); - - /* colors */ - xw.cmap = XDefaultColormap(xw.dpy, xw.scr); - 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, XDefaultDepth(xw.dpy, xw.scr), 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, 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); - - /* 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; - } + wld.fontctx = wld_font_create_context(); + wlloadfonts(usedfont, 0); - if (XParseColor(xw.dpy, xw.cmap, colorname[mousebg], &xmousebg) == 0) { - xmousebg.red = 0x0000; - xmousebg.green = 0x0000; - xmousebg.blue = 0x0000; - } + wlloadcols(); + wlloadcursor(); - XRecolorCursor(xw.dpy, cursor, &xmousefg, &xmousebg); + wl.vis = 0; + wl.h = 2 * borderpx + term.row * wl.ch; + wl.w = 2 * borderpx + term.col * wl.cw; - 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); + wl.surface = wl_compositor_create_surface(wl.cmp); + wl_surface_add_listener(wl.surface, &surflistener, NULL); - xw.netwmpid = XInternAtom(xw.dpy, "_NET_WM_PID", False); - XChangeProperty(xw.dpy, xw.win, xw.netwmpid, XA_CARDINAL, 32, - PropModeReplace, (uchar *)&thispid, 1); + wl.xdgsurface = xdg_shell_get_xdg_surface(wl.shell, wl.surface); + xdg_surface_add_listener(wl.xdgsurface, &xdgsurflistener, NULL); + xdg_surface_set_app_id(wl.xdgsurface, opt_class ? opt_class : termname); - xresettitle(); - XMapWindow(xw.dpy, xw.win); - xhints(); - XSync(xw.dpy, False); + wl.xkb.ctx = xkb_context_new(0); + wlresettitle(); } -int -xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x, int y) +/* + * TODO: Implement something like XftDrawGlyphFontSpec in wld, and then apply a + * similar patch to ae1923d27533ff46400d93765e971558201ca1ee + */ + +void +wldraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) { - float winx = borderpx + x * xw.cw, winy = borderpx + y * xw.ch, xp, yp; - ushort mode, prevmode = USHRT_MAX; + int winx = borderpx + x * wl.cw, winy = borderpx + y * wl.ch, + width = charlen * wl.cw, xp, i; + int frcflags, charexists; + int u8fl, u8fblen, u8cblen, doesexist; + char *u8c, *u8fs; + Rune unicodep; 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; + uint32_t fg, bg, temp; + int oneatatime; - 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; + frcflags = FRC_NORMAL; - /* Skip dummy wide-character spacing. */ - if (mode == ATTR_WDUMMY) - continue; + /* 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; + font = &dc.ibfont; + frcflags = FRC_ITALICBOLD; + } else if (base.mode & ATTR_ITALIC) { + if (dc.ifont.badslant) + base.fg = defaultattr; + font = &dc.ifont; + frcflags = FRC_ITALIC; + } else if (base.mode & ATTR_BOLD) { + if (dc.bfont.badweight) + base.fg = defaultattr; + font = &dc.ifont; + frcflags = FRC_BOLD; + } - /* 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; + if (IS_TRUECOL(base.fg)) { + fg = base.fg | 0xff000000; + } else { + fg = dc.col[base.fg]; + } + + if (IS_TRUECOL(base.bg)) { + bg = base.bg | 0xff000000; + } else { + bg = dc.col[base.bg]; + } + + if (base.mode & ATTR_BOLD) { + /* + * change basic system colors [0-7] + * to bright system colors [8-15] + */ + if (BETWEEN(base.fg, 0, 7) && !(base.mode & ATTR_FAINT)) + fg = dc.col[base.fg + 8]; + + if (base.mode & ATTR_ITALIC) { + font = &dc.ibfont; + frcflags = FRC_ITALICBOLD; + } else { + font = &dc.bfont; + frcflags = FRC_BOLD; } + } - /* Lookup character index with default font. */ - glyphidx = XftCharIndex(xw.dpy, font->match, rune); - if (glyphidx) { - specs[numspecs].font = font->match; - specs[numspecs].glyph = glyphidx; - specs[numspecs].x = (short)xp; - specs[numspecs].y = (short)yp; - xp += runewidth; - numspecs++; - continue; + if (IS_SET(MODE_REVERSE)) { + if (fg == dc.col[defaultfg]) { + fg = dc.col[defaultbg]; + } else { + fg = ~(fg & 0xffffff); } - /* 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; - } + if (bg == dc.col[defaultbg]) { + bg = dc.col[defaultfg]; + } else { + bg = ~(bg & 0xffffff); } + } - /* 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; + if (base.mode & ATTR_REVERSE) { + temp = fg; + fg = bg; + bg = temp; + } - /* - * 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(); + if (base.mode & ATTR_FAINT && !(base.mode & ATTR_BOLD)) { + fg = (fg & (0xff << 24)) + | ((((fg >> 16) & 0xff) / 2) << 16) + | ((((fg >> 8) & 0xff) / 2) << 8) + | ((fg & 0xff) / 2); + } - FcCharSetAddChar(fccharset, rune); + 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) { + wlclear(0, (y == 0)? 0 : winy, borderpx, + ((y >= term.row-1)? wl.h : (winy + wl.ch))); + } + if (x + charlen >= term.col) { + wlclear(winx + width, (y == 0)? 0 : winy, wl.w, + ((y >= term.row-1)? wl.h : (winy + wl.ch))); + } + if (y == 0) + wlclear(winx, 0, winx + width, borderpx); + if (y == term.row-1) + wlclear(winx, winy + wl.ch, winx + width, wl.h); + + /* Clean up the region we want to draw to. */ + wld_fill_rectangle(wld.renderer, bg, winx, winy, width, wl.ch); + + for (xp = winx; bytelen > 0;) { + /* + * Search for the range in the to be printed string of glyphs + * that are in the main font. Then print that range. If + * some glyph is found that is not in the font, do the + * fallback dance. + */ + u8fs = s; + u8fblen = 0; + u8fl = 0; + oneatatime = font->width != wl.cw; + for (;;) { + u8c = s; + u8cblen = utf8decode(s, &unicodep, UTF_SIZ); + s += u8cblen; + bytelen -= u8cblen; + + doesexist = wld_font_ensure_char(font->match, unicodep); + if (doesexist) { + u8fl++; + u8fblen += u8cblen; + if (!oneatatime && bytelen > 0) + continue; + } + + if (u8fl > 0) { + wld_draw_text(wld.renderer, + font->match, fg, xp, + winy + font->ascent, + u8fs, u8fblen, NULL); + xp += wl.cw * u8fl; + } + break; + } + if (doesexist) { + if (oneatatime) + continue; + break; + } + + /* Search the font cache. */ + for (i = 0; i < frclen; i++) { + charexists = wld_font_ensure_char(frc[i].font, unicodep); + /* Everything correct. */ + if (charexists && frc[i].flags == frcflags) + break; + /* We got a default font for a not found glyph. */ + if (!charexists && frc[i].flags == frcflags \ + && frc[i].unicodep == unicodep) { + break; + } + } + + /* Nothing was found. */ + if (i >= 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, unicodep); FcPatternAddCharSet(fcpattern, FC_CHARSET, fccharset); FcPatternAddBool(fcpattern, FC_SCALABLE, 1); @@ -3770,186 +3611,58 @@ xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x */ if (frclen >= LEN(frc)) { frclen = LEN(frc) - 1; - XftFontClose(xw.dpy, frc[frclen].font); + wld_font_close(frc[frclen].font); frc[frclen].unicodep = 0; } - frc[frclen].font = XftFontOpenPattern(xw.dpy, + frc[frclen].font = wld_font_open_pattern(wld.fontctx, fontpattern); frc[frclen].flags = frcflags; - frc[frclen].unicodep = rune; - - glyphidx = XftCharIndex(xw.dpy, frc[frclen].font, rune); + frc[frclen].unicodep = unicodep; - f = frclen; + i = 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; + wld_draw_text(wld.renderer, frc[i].font, fg, + xp, winy + frc[i].font->ascent, + u8c, u8cblen, NULL); - /* 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; + xp += wl.cw * wcwidth(unicodep); } - 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 + 8]; - - 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 + dc.font.ascent + 1, + wld_fill_rectangle(wld.renderer, fg, winx, winy + font->ascent + 1, width, 1); } if (base.mode & ATTR_STRUCK) { - XftDrawRect(xw.draw, fg, winx, winy + 2 * dc.font.ascent / 3, + wld_fill_rectangle(wld.renderer, fg, winx, winy + 2 * font->ascent / 3, width, 1); } - - /* Reset clip to none. */ - XftDrawSetClip(xw.draw, 0); } void -xdrawglyph(Glyph g, int x, int y) +wldrawglyph(Glyph g, int x, int y) { - int numspecs; - XftGlyphFontSpec spec; + static char buf[UTF_SIZ]; + size_t len = utf8encode(g.u, buf); + int width = g.mode & ATTR_WIDE ? 2 : 1; - numspecs = xmakeglyphfontspecs(&spec, &g, 1, x, y); - xdrawglyphfontspecs(&spec, g, numspecs, x, y); + wldraws(buf, g, x, y, width, len); } void -xdrawcursor(void) +wldrawcursor(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; + uint32_t drawcol; LIMIT(oldx, 0, term.col-1); LIMIT(oldy, 0, term.row-1); @@ -3966,7 +3679,11 @@ xdrawcursor(void) og = term.line[oldy][oldx]; if (ena_sel && selected(oldx, oldy)) og.mode ^= ATTR_REVERSE; - xdrawglyph(og, oldx, oldy); + wldrawglyph(og, oldx, oldy); + if (oldx != curx || oldy != term.c.y) { + wl_surface_damage(wl.surface, borderpx + oldx * wl.cw, + borderpx + oldy * wl.ch, wl.cw, wl.ch); + } g.u = term.line[term.c.y][term.c.x].u; @@ -3997,198 +3714,152 @@ xdrawcursor(void) return; /* draw the new one */ - if (xw.state & WIN_FOCUSED) { - switch (xw.cursor) { + if (wl.state & WIN_FOCUSED) { + switch (wl.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); + wldrawglyph(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 - \ + wld_fill_rectangle(wld.renderer, drawcol, + borderpx + curx * wl.cw, + borderpx + (term.c.y + 1) * wl.ch - \ cursorthickness, - xw.cw, cursorthickness); + wl.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); + wld_fill_rectangle(wld.renderer, drawcol, + borderpx + curx * wl.cw, + borderpx + term.c.y * wl.ch, + cursorthickness, wl.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); + wld_fill_rectangle(wld.renderer, drawcol, + borderpx + curx * wl.cw, + borderpx + term.c.y * wl.ch, + wl.cw - 1, 1); + wld_fill_rectangle(wld.renderer, drawcol, + borderpx + curx * wl.cw, + borderpx + term.c.y * wl.ch, + 1, wl.ch - 1); + wld_fill_rectangle(wld.renderer, drawcol, + borderpx + (curx + 1) * wl.cw - 1, + borderpx + term.c.y * wl.ch, + 1, wl.ch - 1); + wld_fill_rectangle(wld.renderer, drawcol, + borderpx + curx * wl.cw, + borderpx + (term.c.y + 1) * wl.ch - 1, + wl.cw, 1); } + wl_surface_damage(wl.surface, borderpx + curx * wl.cw, + borderpx + term.c.y * wl.ch, wl.cw, wl.ch); oldx = curx, oldy = term.c.y; } - void -xsettitle(char *p) +wlsettitle(char *title) { - 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); + xdg_surface_set_title(wl.xdgsurface, title); } void -xresettitle(void) +wlresettitle(void) { - xsettitle(opt_title ? opt_title : "st"); + wlsettitle(opt_title ? opt_title : "st"); } void redraw(void) { tfulldirt(); - draw(); } void draw(void) { + int y, y0; + + for (y = 0; y <= term.bot; ++y) { + if (!term.dirty[y]) + continue; + for (y0 = y; y <= term.bot && term.dirty[y]; ++y); + wl_surface_damage(wl.surface, 0, borderpx + y0 * wl.ch, + wl.w, (y - y0) * wl.ch); + } + + wld_set_target_buffer(wld.renderer, wld.buffer); 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); + wl.framecb = wl_surface_frame(wl.surface); + wl_callback_add_listener(wl.framecb, &framelistener, NULL); + wld_flush(wld.renderer); + wl_surface_attach(wl.surface, wl.buffer, 0, 0); + wl_surface_commit(wl.surface); + /* need to wait to destroy the old buffer until we commit the new + * buffer */ + if (wld.oldbuffer) { + wld_buffer_unreference(wld.oldbuffer); + wld.oldbuffer = 0; + } + needdraw = false; } void drawregion(int x1, int y1, int x2, int y2) { - int i, x, y, ox, numspecs; + int ic, ib, x, y, ox; Glyph base, new; - XftGlyphFontSpec *specs; + char buf[DRAW_BUF_SIZ]; int ena_sel = sel.ob.x != -1 && sel.alt == IS_SET(MODE_ALTSCREEN); - if (!(xw.state & WIN_VISIBLE)) - return; - for (y = y1; y < y2; y++) { if (!term.dirty[y]) continue; term.dirty[y] = 0; - - specs = term.specbuf; - numspecs = xmakeglyphfontspecs(specs, &term.line[y][x1], x2 - x1, x1, y); - - i = ox = 0; - for (x = x1; x < x2 && i < numspecs; x++) { + base = term.line[y][0]; + ic = ib = ox = 0; + for (x = x1; x < x2; x++) { new = term.line[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 (ib > 0 && (ATTRCMP(base, new) + || ib >= DRAW_BUF_SIZ-UTF_SIZ)) { + wldraws(buf, base, ox, y, ic, ib); + ic = ib = 0; } - if (i == 0) { + if (ib == 0) { ox = x; base = new; } - i++; + + ib += utf8encode(new.u, buf+ib); + ic += (new.mode & ATTR_WIDE)? 2 : 1; } - if (i > 0) - xdrawglyphfontspecs(specs, base, i, ox, y); + if (ib > 0) + wldraws(buf, base, ox, y, ic, ib); } - xdrawcursor(); -} - -void -expose(XEvent *ev) -{ - redraw(); -} - -void -visibility(XEvent *ev) -{ - XVisibilityEvent *e = &ev->xvisibility; - - MODBIT(xw.state, e->state != VisibilityFullyObscured, WIN_VISIBLE); + wldrawcursor(); } void -unmap(XEvent *ev) +wlseturgency(int add) { - 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); - } + /* XXX: no urgency equivalent yet in wayland */ } int match(uint mask, uint state) { - return mask == XK_ANY_MOD || mask == (state & ~ignoremod); + return mask == MOD_MASK_ANY || mask == (state & ~(ignoremod)); } void @@ -4198,7 +3869,7 @@ numlock(const Arg *dummy) } char* -kmap(KeySym k, uint state) +kmap(xkb_keysym_t k, uint state) { Key *kp; int i; @@ -4238,38 +3909,179 @@ kmap(KeySym k, uint state) } void -kpress(XEvent *ev) +cresize(int width, int height) +{ + int col, row; + + if (width != 0) + wl.w = width; + if (height != 0) + wl.h = height; + + col = (wl.w - 2 * borderpx) / wl.cw; + row = (wl.h - 2 * borderpx) / wl.ch; + + tresize(col, row); + wlresize(col, row); +} + +void +regglobal(void *data, struct wl_registry *registry, uint32_t name, + const char *interface, uint32_t version) +{ + if (strcmp(interface, "wl_compositor") == 0) { + wl.cmp = wl_registry_bind(registry, name, + &wl_compositor_interface, 3); + } else if (strcmp(interface, "xdg_shell") == 0) { + wl.shell = wl_registry_bind(registry, name, + &xdg_shell_interface, 1); + xdg_shell_add_listener(wl.shell, &xdgshelllistener, NULL); + xdg_shell_use_unstable_version(wl.shell, + XDG_SHELL_VERSION_CURRENT); + } else if (strcmp(interface, "wl_shm") == 0) { + wl.shm = wl_registry_bind(registry, name, &wl_shm_interface, 1); + } else if (strcmp(interface, "wl_seat") == 0) { + wl.seat = wl_registry_bind(registry, name, + &wl_seat_interface, 4); + } else if (strcmp(interface, "wl_data_device_manager") == 0) { + wl.datadevmanager = wl_registry_bind(registry, name, + &wl_data_device_manager_interface, 1); + } else if (strcmp(interface, "wl_output") == 0) { + /* bind to outputs so we can get surface enter events */ + wl_registry_bind(registry, name, &wl_output_interface, 2); + } +} + +void +regglobalremove(void *data, struct wl_registry *registry, uint32_t name) +{ +} + +void +surfenter(void *data, struct wl_surface *surface, struct wl_output *output) +{ + wl.vis++; + if (!(wl.state & WIN_VISIBLE)) + wl.state |= WIN_VISIBLE; +} + +void +surfleave(void *data, struct wl_surface *surface, struct wl_output *output) +{ + if (--wl.vis == 0) + wl.state &= ~WIN_VISIBLE; +} + +void +framedone(void *data, struct wl_callback *callback, uint32_t msecs) +{ + wl_callback_destroy(callback); + wl.framecb = NULL; + if (needdraw && wl.state & WIN_VISIBLE) { + draw(); + } +} + +void +kbdkeymap(void *data, struct wl_keyboard *keyboard, uint32_t format, int32_t fd, + uint32_t size) { - XKeyEvent *e = &ev->xkey; - KeySym ksym; - char buf[32], *customkey; + char *string; + + if (format != WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1) { + close(fd); + return; + } + + string = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0); + + if (string == MAP_FAILED) { + close(fd); + return; + } + + wl.xkb.keymap = xkb_keymap_new_from_string(wl.xkb.ctx, string, + XKB_KEYMAP_FORMAT_TEXT_V1, 0); + munmap(string, size); + close(fd); + wl.xkb.state = xkb_state_new(wl.xkb.keymap); + + wl.xkb.ctrl = xkb_keymap_mod_get_index(wl.xkb.keymap, XKB_MOD_NAME_CTRL); + wl.xkb.alt = xkb_keymap_mod_get_index(wl.xkb.keymap, XKB_MOD_NAME_ALT); + wl.xkb.shift = xkb_keymap_mod_get_index(wl.xkb.keymap, XKB_MOD_NAME_SHIFT); + wl.xkb.logo = xkb_keymap_mod_get_index(wl.xkb.keymap, XKB_MOD_NAME_LOGO); + + wl.xkb.mods = 0; +} + +void +kbdenter(void *data, struct wl_keyboard *keyboard, uint32_t serial, + struct wl_surface *surface, struct wl_array *keys) +{ + wl.state |= WIN_FOCUSED; + if (IS_SET(MODE_FOCUS)) + ttywrite("\033[I", 3); + /* need to redraw the cursor */ + needdraw = true; +} + +void +kbdleave(void *data, struct wl_keyboard *keyboard, uint32_t serial, + struct wl_surface *surface) +{ + /* selection offers are invalidated when we lose keyboard focus */ + wl.seloffer = NULL; + wl.state &= ~WIN_FOCUSED; + if (IS_SET(MODE_FOCUS)) + ttywrite("\033[O", 3); + /* need to redraw the cursor */ + needdraw = true; + /* disable key repeat */ + repeat.len = 0; +} + +void +kbdkey(void *data, struct wl_keyboard *keyboard, uint32_t serial, uint32_t time, + uint32_t key, uint32_t state) +{ + xkb_keysym_t ksym; + char buf[32], *str; int len; Rune c; - Status status; Shortcut *bp; if (IS_SET(MODE_KBDLOCK)) return; - len = XmbLookupString(xw.xic, e, buf, sizeof buf, &ksym, &status); + if (state == WL_KEYBOARD_KEY_STATE_RELEASED) { + if (repeat.key == key) + repeat.len = 0; + return; + } + + ksym = xkb_state_key_get_one_sym(wl.xkb.state, key + 8); + len = xkb_keysym_to_utf8(ksym, buf, sizeof buf); + if (len > 0) + --len; + /* 1. shortcuts */ for (bp = shortcuts; bp < shortcuts + LEN(shortcuts); bp++) { - if (ksym == bp->keysym && match(bp->mod, e->state)) { + if (ksym == bp->keysym && match(bp->mod, wl.xkb.mods)) { bp->func(&(bp->arg)); return; } } /* 2. custom keys from config.h */ - if ((customkey = kmap(ksym, e->state))) { - ttysend(customkey, strlen(customkey)); - return; + if ((str = kmap(ksym, wl.xkb.mods))) { + len = strlen(str); + goto send; } /* 3. composed string from input method */ if (len == 0) return; - if (len == 1 && e->state & Mod1Mask) { + if (len == 1 && wl.xkb.mods & MOD_MASK_ALT) { if (IS_SET(MODE_8BIT)) { if (*buf < 0177) { c = *buf | 0x80; @@ -4281,101 +4093,327 @@ kpress(XEvent *ev) len = 2; } } - ttysend(buf, len); + /* convert character to control character */ + else if (len == 1 && wl.xkb.mods & MOD_MASK_CTRL) { + if ((*buf >= '@' && *buf < '\177') || *buf == ' ') + *buf &= 0x1F; + else if (*buf == '2') *buf = '\000'; + else if (*buf >= '3' && *buf <= '7') + *buf -= ('3' - '\033'); + else if (*buf == '8') *buf = '\177'; + else if (*buf == '/') *buf = '_' & 0x1F; + } + + str = buf; + +send: + memcpy(repeat.str, str, len); + repeat.key = key; + repeat.len = len; + repeat.started = false; + clock_gettime(CLOCK_MONOTONIC, &repeat.last); + ttysend(str, len); +} + +void +kbdmodifiers(void *data, struct wl_keyboard *keyboard, uint32_t serial, + uint32_t dep, uint32_t lat, uint32_t lck, uint32_t group) +{ + xkb_mod_mask_t mod_mask; + + xkb_state_update_mask(wl.xkb.state, dep, lat, lck, group, 0, 0); + + mod_mask = xkb_state_serialize_mods(wl.xkb.state, XKB_STATE_MODS_EFFECTIVE); + wl.xkb.mods = 0; + + if (mod_mask & (1 << wl.xkb.ctrl)) + wl.xkb.mods |= MOD_MASK_CTRL; + if (mod_mask & (1 << wl.xkb.alt)) + wl.xkb.mods |= MOD_MASK_ALT; + if (mod_mask & (1 << wl.xkb.shift)) + wl.xkb.mods |= MOD_MASK_SHIFT; + if (mod_mask & (1 << wl.xkb.logo)) + wl.xkb.mods |= MOD_MASK_LOGO; } +void +kbdrepeatinfo(void *data, struct wl_keyboard *keyboard, int32_t rate, + int32_t delay) +{ + keyrepeatdelay = delay; + keyrepeatinterval = 1000 / rate; +} void -cmessage(XEvent *e) +ptrenter(void *data, struct wl_pointer *pointer, uint32_t serial, + struct wl_surface *surface, wl_fixed_t x, wl_fixed_t y) { - /* - * 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; + struct wl_cursor_image *img = cursor.cursor->images[0]; + struct wl_buffer *buffer; + + wl_pointer_set_cursor(pointer, serial, cursor.surface, + img->hotspot_x, img->hotspot_y); + buffer = wl_cursor_image_get_buffer(img); + wl_surface_attach(cursor.surface, buffer, 0, 0); + wl_surface_damage(cursor.surface, 0, 0, img->width, img->height); + wl_surface_commit(cursor.surface); +} + +void +ptrleave(void *data, struct wl_pointer *pointer, uint32_t serial, + struct wl_surface *surface) +{ +} + +void +ptrmotion(void *data, struct wl_pointer * pointer, uint32_t serial, + wl_fixed_t x, wl_fixed_t y) +{ + int oldey, oldex, oldsby, oldsey; + + if (IS_SET(MODE_MOUSE)) { + wlmousereportmotion(x, y); + return; + } + + wl.px = wl_fixed_to_int(x); + wl.py = wl_fixed_to_int(y); + + 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(); + + if (oldey != sel.oe.y || oldex != sel.oe.x) + tsetdirt(MIN(sel.nb.y, oldsby), MAX(sel.ne.y, oldsey)); +} + +void +ptrbutton(void * data, struct wl_pointer * pointer, uint32_t serial, + uint32_t time, uint32_t button, uint32_t state) +{ + MouseShortcut *ms; + + if (IS_SET(MODE_MOUSE) && !(wl.xkb.mods & forceselmod)) { + wlmousereportbutton(button, state); + return; + } + + switch (state) { + case WL_POINTER_BUTTON_STATE_RELEASED: + if (button == BTN_MIDDLE) { + selpaste(NULL); + } else if (button == BTN_LEFT) { + if (sel.mode == SEL_READY) { + getbuttoninfo(); + selcopy(serial); + } else + selclear(); + sel.mode = SEL_IDLE; + tsetdirt(sel.nb.y, sel.ne.y); + } + break; + + case WL_POINTER_BUTTON_STATE_PRESSED: + for (ms = mshortcuts; ms < mshortcuts + LEN(mshortcuts); ms++) { + if (button == ms->b && match(ms->mask, wl.xkb.mods)) { + ttysend(ms->s, strlen(ms->s)); + return; + } } - } else if (e->xclient.data.l[0] == xw.wmdeletewin) { - /* Send SIGHUP to shell */ - kill(pid, SIGHUP); - exit(0); + + if (button == BTN_LEFT) { + /* Clear previous selection, logically and visually. */ + selclear(); + sel.mode = SEL_EMPTY; + sel.type = SEL_REGULAR; + sel.oe.x = sel.ob.x = x2col(wl.px); + sel.oe.y = sel.ob.y = y2row(wl.py); + + /* + * If the user clicks below predefined timeouts + * specific snapping behaviour is exposed. + */ + if (time - sel.tclick2 <= tripleclicktimeout) { + sel.snap = SNAP_LINE; + } else if (time - 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 = time; + } + break; } } void -cresize(int width, int height) +ptraxis(void * data, struct wl_pointer * pointer, uint32_t time, uint32_t axis, + wl_fixed_t value) { - int col, row; + Axiskey *ak; + int dir = value > 0 ? +1 : -1; - if (width != 0) - xw.w = width; - if (height != 0) - xw.h = height; + if (IS_SET(MODE_MOUSE) && !(wl.xkb.mods & forceselmod)) { + wlmousereportaxis(axis, value); + return; + } - col = (xw.w - 2 * borderpx) / xw.cw; - row = (xw.h - 2 * borderpx) / xw.ch; + for (ak = ashortcuts; ak < ashortcuts + LEN(ashortcuts); ak++) { + if (axis == ak->axis && dir == ak->dir + && match(ak->mask, wl.xkb.mods)) { + ttysend(ak->s, strlen(ak->s)); + return; + } + } +} - tresize(col, row); - xresize(col, row); +void +xdgshellping(void *data, struct xdg_shell *shell, uint32_t serial) +{ + xdg_shell_pong(shell, serial); } void -resize(XEvent *e) +xdgsurfconfigure(void *data, struct xdg_surface *surf, int32_t w, int32_t h, + struct wl_array *states, uint32_t serial) { - if (e->xconfigure.width == xw.w && e->xconfigure.height == xw.h) + xdg_surface_ack_configure(surf, serial); + if (w == wl.w && h == wl.h) return; + cresize(w, h); + if (wl.configured) + ttyresize(); + else + wl.configured = true; +} - cresize(e->xconfigure.width, e->xconfigure.height); - ttyresize(); +void +xdgsurfclose(void *data, struct xdg_surface *surf) +{ + /* Send SIGHUP to shell */ + kill(pid, SIGHUP); + exit(0); +} + +void +datadevoffer(void *data, struct wl_data_device *datadev, + struct wl_data_offer *offer) +{ + wl_data_offer_add_listener(offer, &dataofferlistener, NULL); +} + +void +datadeventer(void *data, struct wl_data_device *datadev, uint32_t serial, + struct wl_surface *surf, wl_fixed_t x, wl_fixed_t y, + struct wl_data_offer *offer) +{ +} + +void +datadevleave(void *data, struct wl_data_device *datadev) +{ +} + +void +datadevmotion(void *data, struct wl_data_device *datadev, uint32_t time, + wl_fixed_t x, wl_fixed_t y) +{ +} + +void +datadevdrop(void *data, struct wl_data_device *datadev) +{ +} + +void +datadevselection(void *data, struct wl_data_device *datadev, + struct wl_data_offer *offer) +{ + if (offer && (uintptr_t) wl_data_offer_get_user_data(offer) == 1) + wl.seloffer = offer; + else + wl.seloffer = NULL; +} + +void +dataofferoffer(void *data, struct wl_data_offer *offer, const char *mimetype) +{ + /* mark the offer as usable if it supports plain text */ + if (strncmp(mimetype, "text/plain", 10) == 0) + wl_data_offer_set_user_data(offer, (void *)(uintptr_t) 1); +} + +void +datasrctarget(void *data, struct wl_data_source *source, const char *mimetype) +{ +} + +void +datasrcsend(void *data, struct wl_data_source *source, const char *mimetype, + int32_t fd) +{ + char *buf = sel.primary; + int len = strlen(sel.primary); + ssize_t ret; + while ((ret = write(fd, buf, MIN(len, BUFSIZ))) > 0) { + len -= ret; + buf += ret; + } + close(fd); +} + +void +datasrccancelled(void *data, struct wl_data_source *source) +{ + if (sel.source == source) { + sel.source = NULL; + selclear(); + } + wl_data_source_destroy(source); } 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; + int wlfd = wl_display_get_fd(wl.dpy), blinkset = 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); + ulong msecs; - cresize(w, h); + /* Look for initial configure. */ + wl_display_roundtrip(wl.dpy); + if (!wl.configured) + cresize(wl.w, wl.h); ttynew(); ttyresize(); + draw(); clock_gettime(CLOCK_MONOTONIC, &last); lastblink = last; - for (xev = actionfps;;) { + for (;;) { FD_ZERO(&rfd); FD_SET(cmdfd, &rfd); - FD_SET(xfd, &rfd); + FD_SET(wlfd, &rfd); - if (pselect(MAX(xfd, cmdfd)+1, &rfd, NULL, NULL, tv, NULL) < 0) { + if (pselect(MAX(wlfd, 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) { @@ -4385,60 +4423,54 @@ run(void) } } - if (FD_ISSET(xfd, &rfd)) - xev = actionfps; + if (FD_ISSET(wlfd, &rfd)) { + if (wl_display_dispatch(wl.dpy) == -1) + die("Connection error\n"); + } 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; + msecs = -1; + + if (blinkset && blinktimeout) { + if (TIMEDIFF(now, lastblink) >= blinktimeout) { + tsetdirtattr(ATTR_BLINK); + term.mode ^= MODE_BLINK; + lastblink = now; + } else { + msecs = MIN(msecs, blinktimeout - \ + TIMEDIFF(now, lastblink)); + } } - deltatime = TIMEDIFF(now, last); - if (deltatime > 1000 / (xev ? xfps : actionfps)) { - dodraw = 1; - last = now; + if (repeat.len > 0) { + if (TIMEDIFF(now, repeat.last) >= \ + (repeat.started ? keyrepeatinterval : \ + keyrepeatdelay)) { + repeat.started = true; + repeat.last = now; + ttysend(repeat.str, repeat.len); + } else { + msecs = MIN(msecs, (repeat.started ? \ + keyrepeatinterval : keyrepeatdelay) - \ + TIMEDIFF(now, repeat.last)); + } } - if (dodraw) { - while (XPending(xw.dpy)) { - XNextEvent(xw.dpy, &ev); - if (XFilterEvent(&ev, None)) - continue; - if (handler[ev.type]) - (handler[ev.type])(&ev); + if (needdraw && wl.state & WIN_VISIBLE) { + if (!wl.framecb) { + draw(); } + } - 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; - } - } + if (msecs == -1) { + tv = NULL; + } else { + drawtimeout.tv_nsec = 1E6 * msecs; + drawtimeout.tv_sec = 0; + tv = &drawtimeout; } + + wl_display_dispatch_pending(wl.dpy); + wl_display_flush(wl.dpy); } } @@ -4458,11 +4490,7 @@ usage(void) int main(int argc, char *argv[]) { - uint cols = 80, rows = 24; - - xw.l = xw.t = 0; - xw.isfixed = False; - xw.cursor = cursorshape; + wl.cursor = cursorshape; ARGBEGIN { case 'a': @@ -4478,13 +4506,6 @@ main(int argc, char *argv[]) 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; @@ -4516,9 +4537,8 @@ main(int argc, char *argv[]) opt_title = basename(xstrdup(argv[0])); } setlocale(LC_CTYPE, ""); - XSetLocaleModifiers(""); - tnew(MAX(cols, 1), MAX(rows, 1)); - xinit(); + tnew(80, 24); + wlinit(); selinit(); run(); From e2ee5ee6114eb74bb08cb9abe5a3020203e92688 Mon Sep 17 00:00:00 2001 From: Michael Forney Date: Fri, 20 Jan 2017 00:06:39 -0800 Subject: [PATCH 002/129] Split X-specific code into x.c --- Makefile | 5 +- config.def.h | 64 +- st.c | 2080 +++----------------------------------------------- st.h | 272 +++++++ win.h | 29 + x.c | 1766 ++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 2195 insertions(+), 2021 deletions(-) create mode 100644 st.h create mode 100644 win.h create mode 100644 x.c diff --git a/Makefile b/Makefile index fb026c4..d8595fe 100644 --- a/Makefile +++ b/Makefile @@ -3,7 +3,7 @@ include config.mk -SRC = st.c +SRC = st.c x.c OBJ = ${SRC:.c=.o} all: options st @@ -21,6 +21,9 @@ config.h: @echo CC $< @${CC} -c ${CFLAGS} $< +st.o: config.h st.h win.h +x.o: arg.h st.h win.h + ${OBJ}: config.h config.mk st: ${OBJ} diff --git a/config.def.h b/config.def.h index a719e36..fd80923 100644 --- a/config.def.h +++ b/config.def.h @@ -5,8 +5,8 @@ * * font: see http://freedesktop.org/software/fontconfig/fontconfig-user.html */ -static char font[] = "Liberation Mono:pixelsize=12:antialias=true:autohint=true"; -static int borderpx = 2; +char font[] = "Liberation Mono:pixelsize=12:antialias=true:autohint=true"; +int borderpx = 2; /* * What program is execed by st depends of these precedence rules: @@ -24,8 +24,8 @@ static char stty_args[] = "stty raw pass8 nl -echo -iexten -cstopb 38400"; static char vtiden[] = "\033[?6c"; /* Kerning / character bounding-box multipliers */ -static float cwscale = 1.0; -static float chscale = 1.0; +float cwscale = 1.0; +float chscale = 1.0; /* * word delimiter string @@ -35,26 +35,26 @@ static float chscale = 1.0; static char worddelimiters[] = " "; /* selection timeouts (in milliseconds) */ -static unsigned int doubleclicktimeout = 300; -static unsigned int tripleclicktimeout = 600; +unsigned int doubleclicktimeout = 300; +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; -static unsigned int actionfps = 30; +unsigned int xfps = 120; +unsigned int actionfps = 30; /* * blinking timeout (set to 0 to disable blinking) for the terminal blinking * attribute. */ -static unsigned int blinktimeout = 800; +unsigned int blinktimeout = 800; /* * thickness of underline and bar cursors */ -static unsigned int cursorthickness = 2; +unsigned int cursorthickness = 2; /* * bell volume. It must be a value between -100 and 100. Use 0 for disabling @@ -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 @@ -83,7 +83,7 @@ static char termname[] = "st-256color"; static unsigned int tabspaces = 8; /* Terminal colors (16 first used in escape sequence) */ -static const char *colorname[] = { +const char *colorname[] = { /* 8 normal colors */ "black", "red3", @@ -116,10 +116,10 @@ static const char *colorname[] = { * 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; +unsigned int defaultfg = 7; +unsigned int defaultbg = 0; +unsigned int defaultcs = 256; +unsigned int defaultrcs = 257; /* * Default shape of cursor @@ -128,33 +128,33 @@ static unsigned int defaultrcs = 257; * 6: Bar ("|") * 7: Snowman ("☃") */ -static unsigned int cursorshape = 2; +unsigned int cursorshape = 2; /* * Default columns and rows numbers */ -static unsigned int cols = 80; -static unsigned int rows = 24; +unsigned int cols = 80; +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; +unsigned int mouseshape = XC_xterm; +unsigned int mousefg = 7; +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; +unsigned int defaultattr = 11; /* * Internal mouse shortcuts. * Beware that overloading Button1 will disable the selection. */ -static MouseShortcut mshortcuts[] = { +MouseShortcut mshortcuts[] = { /* button mask string */ { Button4, XK_ANY_MOD, "\031" }, { Button5, XK_ANY_MOD, "\005" }, @@ -163,15 +163,15 @@ static MouseShortcut mshortcuts[] = { /* Internal keyboard shortcuts. */ #define MODKEY Mod1Mask -static Shortcut shortcuts[] = { +Shortcut shortcuts[] = { /* mask keysym function argument */ { XK_ANY_MOD, XK_Break, sendbreak, {.i = 0} }, { ControlMask, XK_Print, toggleprinter, {.i = 0} }, { ShiftMask, XK_Print, printscreen, {.i = 0} }, { XK_ANY_MOD, XK_Print, printsel, {.i = 0} }, - { MODKEY|ShiftMask, XK_Prior, xzoom, {.f = +1} }, - { MODKEY|ShiftMask, XK_Next, xzoom, {.f = -1} }, - { MODKEY|ShiftMask, XK_Home, xzoomreset, {.f = 0} }, + { MODKEY|ShiftMask, XK_Prior, zoom, {.f = +1} }, + { MODKEY|ShiftMask, XK_Next, zoom, {.f = -1} }, + { MODKEY|ShiftMask, XK_Home, zoomreset, {.f = 0} }, { ShiftMask, XK_Insert, selpaste, {.i = 0} }, { MODKEY|ShiftMask, XK_Insert, clippaste, {.i = 0} }, { MODKEY|ShiftMask, XK_C, clipcopy, {.i = 0} }, @@ -222,7 +222,7 @@ static uint ignoremod = Mod2Mask|XK_SWITCH_MOD; * Note that if you want to use ShiftMask with selmasks, set this to an other * modifier, set to 0 to not use it. */ -static uint forceselmod = ShiftMask; +uint forceselmod = ShiftMask; /* * This is the huge key array which defines all compatibility to the Linux @@ -451,7 +451,7 @@ static Key key[] = { * ButtonRelease and MotionNotify. * If no match is found, regular selection is used. */ -static uint selmasks[] = { +uint selmasks[] = { [SEL_RECTANGULAR] = Mod1Mask, }; @@ -459,7 +459,7 @@ static uint selmasks[] = { * Printable characters in ASCII, used to estimate the advance width * of single wide characters. */ -static char ascii_printable[] = +char ascii_printable[] = " !\"#$%&'()*+,-./0123456789:;<=>?" "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_" "`abcdefghijklmnopqrstuvwxyz{|}~"; diff --git a/st.c b/st.c index fbcd9e0..1e4196e 100644 --- a/st.c +++ b/st.c @@ -21,23 +21,21 @@ #include #include #include -#include -#include -#include -#include -#include -#include -#include #include #include -#include "arg.h" +/* X11 */ +#include +#include char *argv0; #define Glyph Glyph_ #define Font Font_ +#include "win.h" +#include "st.h" + #if defined(__linux) #include #elif defined(__OpenBSD__) || defined(__NetBSD__) || defined(__APPLE__) @@ -46,67 +44,24 @@ char *argv0; #include #endif - -/* XEMBED messages */ -#define XEMBED_FOCUS_IN 4 -#define XEMBED_FOCUS_OUT 5 - /* Arbitrary sizes */ #define UTF_INVALID 0xFFFD -#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 XK_ANY_MOD UINT_MAX -#define XK_NO_MOD 0 -#define XK_SWITCH_MOD (1<<13) /* 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 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 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) /* constants */ #define ISO14755CMD "dmenu -w %lu -p codepoint: ] [;]] []] */ typedef struct { @@ -235,56 +115,6 @@ typedef struct { int narg; /* nb of args */ } STREscape; -/* 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 */ - XftGlyphFontSpec *specbuf; /* font spec buffer used for rendering */ - TCursor c; /* cursor */ - 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 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 */ - 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; @@ -295,89 +125,26 @@ typedef struct { signed char crlf; /* crlf mode */ } Key; -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; - -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 numlock(const Arg *); static void selpaste(const Arg *); -static void xzoom(const Arg *); -static void xzoomabs(const Arg *); -static void xzoomreset(const Arg *); +static void zoom(const Arg *); +static void zoomabs(const Arg *); +static void zoomreset(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. */ +/* 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(LEN(colorname), 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 sigchld(int); -static void run(void); static void csidump(void); static void csihandle(void); @@ -389,7 +156,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); @@ -403,7 +169,6 @@ 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); @@ -415,8 +180,6 @@ static void tsetattr(int *, int); static void tsetchar(Rune, Glyph *, 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 void tfulldirt(void); static void techo(Rune); @@ -425,151 +188,53 @@ 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 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 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 size_t utf8validate(Rune *, size_t); 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; +TermWindow win; +Term term; +Selection sel; +int cmdfd; +pid_t pid; +char **opt_cmd = NULL; +char *opt_class = NULL; +char *opt_embed = NULL; +char *opt_font = NULL; +char *opt_io = NULL; +char *opt_line = NULL; +char *opt_name = NULL; +char *opt_title = NULL; +int oldbutton = 3; /* button event on startup: 3 = release */ + static CSIEscape csiescseq; static STREscape strescseq; -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 char *usedfont = NULL; -static double usedfontsize = 0; -static double defaultfontsize = 0; + +char *usedfont = NULL; +double usedfontsize = 0; +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; +/* config.h array lengths */ +size_t colornamelen = LEN(colorname); +size_t mshortcutslen = LEN(mshortcuts); +size_t shortcutslen = LEN(shortcuts); +size_t selmaskslen = LEN(selmasks); ssize_t xwrite(int fd, const char *s, size_t len) @@ -714,16 +379,13 @@ selinit(void) 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) { x -= borderpx; - x /= xw.cw; + x /= win.cw; return LIMIT(x, 0, term.col-1); } @@ -732,7 +394,7 @@ int y2row(int y) { y -= borderpx; - y /= xw.ch; + y /= win.ch; return LIMIT(y, 0, term.row-1); } @@ -867,141 +529,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; - - 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; - } - } - - 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) { @@ -1056,149 +583,26 @@ getsel(void) return str; } -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); + xselpaste(); } 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); - } + xclipcopy(); } void clippaste(const Arg *dummy) { - Atom clipboard; - - clipboard = XInternAtom(xw.dpy, "CLIPBOARD", 0); - XConvertSelection(xw.dpy, clipboard, sel.xtarget, clipboard, - xw.win, CurrentTime); + xclippaste(); } void -selclear(XEvent *e) +selclear(void) { if (sel.ob.x == -1) return; @@ -1207,120 +611,6 @@ selclear(XEvent *e) tsetdirt(sel.nb.y, sel.ne.y); } -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); -} - -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, ...) { @@ -1337,7 +627,6 @@ execsh(void) { char **args, *sh, *prog; const struct passwd *pw; - char buf[sizeof(long) * 8 + 1]; errno = 0; if ((pw = getpwuid(getuid())) == NULL) { @@ -1358,8 +647,6 @@ execsh(void) prog = sh; args = (opt_cmd) ? opt_cmd : (char *[]) {prog, NULL}; - snprintf(buf, sizeof(buf), "%lu", xw.win); - unsetenv("COLUMNS"); unsetenv("LINES"); unsetenv("TERMCAP"); @@ -1368,7 +655,7 @@ execsh(void) setenv("SHELL", sh, 1); setenv("HOME", pw->pw_dir, 1); setenv("TERM", termname, 1); - setenv("WINDOWID", buf, 1); + xsetenv(); signal(SIGCHLD, SIG_DFL); signal(SIGHUP, SIG_DFL); @@ -1606,8 +893,8 @@ ttyresize(void) w.ws_row = term.row; w.ws_col = term.col; - w.ws_xpixel = xw.tw; - w.ws_ypixel = xw.th; + w.ws_xpixel = win.tw; + w.ws_ypixel = win.th; if (ioctl(cmdfd, TIOCSWINSZ, &w) < 0) fprintf(stderr, "Couldn't set window size: %s\n", strerror(errno)); } @@ -1771,7 +1058,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) { @@ -1917,7 +1204,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; @@ -2368,7 +1655,7 @@ csihandle(void) tputtab(csiescseq.arg[0]); break; case 'J': /* ED -- Clear screen */ - selclear(NULL); + selclear(); switch (csiescseq.arg[0]) { case 0: /* below */ tclearregion(term.c.x, term.c.y, term.col-1, term.c.y); @@ -2475,7 +1762,7 @@ csihandle(void) if (!BETWEEN(csiescseq.arg[0], 0, 6)) { goto unknown; } - xw.cursor = csiescseq.arg[0]; + win.cursor = csiescseq.arg[0]; break; default: goto unknown; @@ -2642,12 +1929,13 @@ tprinter(char *s, size_t len) void iso14755(const Arg *arg) { - char cmd[sizeof(ISO14755CMD) + NUMMAXLEN(xw.win)]; + unsigned long id = xwinid(); + char cmd[sizeof(ISO14755CMD) + NUMMAXLEN(id)]; FILE *p; char *us, *e, codepoint[9], uc[UTF_SIZ]; unsigned long utf32; - snprintf(cmd, sizeof(cmd), ISO14755CMD, xw.win); + snprintf(cmd, sizeof(cmd), ISO14755CMD, id); if (!(p = popen(cmd, "r"))) return; @@ -2833,10 +2121,10 @@ tcontrolcode(uchar ascii) /* backwards compatibility to xterm */ strhandle(); } else { - if (!(xw.state & WIN_FOCUSED)) + if (!(win.state & WIN_FOCUSED)) xseturgency(1); if (bellvolume) - XkbBell(xw.dpy, xw.win, bellvolume, (Atom)NULL); + xbell(bellvolume); } break; case '\033': /* ESC */ @@ -2968,7 +2256,7 @@ eschandle(uchar ascii) break; case 'c': /* RIS -- Reset to inital state */ treset(); - xresettitle(); + resettitle(); xloadcols(); break; case '=': /* DECPAM -- Application keypad */ @@ -3109,7 +2397,7 @@ tputc(Rune u) 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)) { @@ -3177,7 +2465,7 @@ tresize(int col, int row) } /* resize to new width */ - term.specbuf = xrealloc(term.specbuf, col * sizeof(XftGlyphFontSpec)); + term.specbuf = xrealloc(term.specbuf, col * sizeof(GlyphFontSpec)); /* resize to new height */ term.line = xrealloc(term.line, row * sizeof(Line)); @@ -3228,993 +2516,66 @@ tresize(int col, int row) } void -xresize(int col, int row) +zoom(const Arg *arg) { - 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, - DefaultDepth(xw.dpy, xw.scr)); - XftDrawChange(xw.draw, xw.buf); - xclear(0, 0, xw.w, xw.h); -} + Arg larg; -ushort -sixd_to_16bit(int x) -{ - return x == 0 ? 0 : 0x3737 + 0x2828 * x; + larg.f = usedfontsize + arg->f; + zoomabs(&larg); } -int -xloadcolor(int i, const char *name, Color *ncolor) +void +zoomabs(const Arg *arg) { - 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); + xunloadfonts(); + xloadfonts(usedfont, arg->f); + cresize(0, 0); + ttyresize(); + redraw(); + xhints(); } void -xloadcols(void) +zoomreset(const Arg *arg) { - int i; - static int loaded; - Color *cp; + Arg larg; - if (loaded) { - for (cp = dc.col; cp < &dc.col[LEN(dc.col)]; ++cp) - XftColorFree(xw.dpy, xw.vis, xw.cmap, cp); + if (defaultfontsize > 0) { + larg.f = defaultfontsize; + zoomabs(&larg); } - - 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]); - else - die("Could not allocate color %d\n", i); - } - 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; } -/* - * Absolute coordinates. - */ void -xclear(int x1, int y1, int x2, int y2) +resettitle(void) { - XftDrawRect(xw.draw, - &dc.col[IS_SET(MODE_REVERSE)? defaultfg : defaultbg], - x1, y1, x2-x1, y2-y1); + xsettitle(opt_title ? opt_title : "st"); } void -xhints(void) +redraw(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); + tfulldirt(); + draw(); } int -xgeommasktogravity(int mask) +match(uint mask, uint state) { - switch (mask & (XNegative|YNegative)) { - case 0: - return NorthWestGravity; - case XNegative: - return NorthEastGravity; - case YNegative: - return SouthWestGravity; - } - - return SouthEastGravity; + return mask == XK_ANY_MOD || mask == (state & ~ignoremod); } -int -xloadfont(Font *f, FcPattern *pattern) +void +numlock(const Arg *dummy) { - FcPattern *configured; - FcPattern *match; - FcResult result; - XGlyphInfo extents; - int wantattr, haveattr; + term.numlock ^= 1; +} - /* - * 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); - - 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.vis = XDefaultVisual(xw.dpy, xw.scr); - - /* font */ - if (!FcInit()) - die("Could not init fontconfig.\n"); - - usedfont = (opt_font == NULL)? font : opt_font; - xloadfonts(usedfont, 0); - - /* colors */ - xw.cmap = XDefaultColormap(xw.dpy, xw.scr); - 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, XDefaultDepth(xw.dpy, xw.scr), 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, 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); - - /* 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); - - 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; - } - - /* 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 + 8]; - - 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 + dc.font.ascent + 1, - width, 1); - } - - if (base.mode & ATTR_STRUCK) { - XftDrawRect(xw.draw, fg, winx, winy + 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); -} - -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; - - for (y = y1; y < y2; y++) { - if (!term.dirty[y]) - continue; - - term.dirty[y] = 0; - - specs = term.specbuf; - numspecs = xmakeglyphfontspecs(specs, &term.line[y][x1], x2 - x1, x1, y); - - i = ox = 0; - for (x = x1; x < x2 && i < numspecs; x++) { - new = term.line[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); - } - 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; -} - -char* -kmap(KeySym k, uint state) -{ - Key *kp; - int i; +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++) { @@ -4250,211 +2611,23 @@ kmap(KeySym k, uint state) 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) { int col, row; if (width != 0) - xw.w = width; + win.w = width; if (height != 0) - xw.h = height; + win.h = height; - col = (xw.w - 2 * borderpx) / xw.cw; - row = (xw.h - 2 * borderpx) / xw.ch; + col = (win.w - 2 * borderpx) / win.cw; + row = (win.h - 2 * borderpx) / win.ch; tresize(col, row); xresize(col, row); } -void -resize(XEvent *e) -{ - if (e->xconfigure.width == xw.w && e->xconfigure.height == xw.h) - return; - - cresize(e->xconfigure.width, e->xconfigure.height); - ttyresize(); -} - -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; - } - } - } - } -} - void usage(void) { @@ -4467,72 +2640,3 @@ usage(void) " [-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; - 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; -} - diff --git a/st.h b/st.h new file mode 100644 index 0000000..44d4938 --- /dev/null +++ b/st.h @@ -0,0 +1,272 @@ +/* See LICENSE for license details. */ + +/* Arbitrary sizes */ +#define UTF_SIZ 4 + +/* 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 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 TRUECOLOR(r,g,b) (1 << 24 | (r) << 16 | (g) << 8 | (b)) +#define IS_TRUECOL(x) (1 << 24 & (x)) + +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 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 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 +}; + +enum window_state { + WIN_VISIBLE = 1, + WIN_FOCUSED = 2 +}; + +typedef unsigned char uchar; +typedef unsigned int uint; +typedef unsigned long ulong; +typedef unsigned short ushort; + +typedef uint_least32_t Rune; + +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; + int y; + char state; +} TCursor; + +/* 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 */ + GlyphFontSpec *specbuf; /* font spec buffer used for rendering */ + TCursor c; /* cursor */ + 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 numlock; /* lock numbers in keyboard */ + int *tabs; +} Term; + +/* 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 */ + char state; /* focus, redraw, visible */ + int cursor; /* cursor style */ +} TermWindow; + +typedef struct { + uint b; + uint mask; + char *s; +} MouseShortcut; + +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; + int alt; + struct timespec tclick1; + struct timespec tclick2; + + //Atom xtarget; +} Selection; + +typedef union { + int i; + uint ui; + float f; + const void *v; +} Arg; + +typedef struct { + uint mod; + KeySym keysym; + void (*func)(const Arg *); + const Arg arg; +} Shortcut; + +void die(const char *, ...); +void redraw(void); + +int tattrset(int); +void tnew(int, int); +void tsetdirt(int, int); +void tsetdirtattr(int); +int match(uint, uint); +void ttynew(void); +size_t ttyread(void); +void ttyresize(void); +void ttysend(char *, size_t); +void ttywrite(const char *, size_t); + +void resettitle(void); + +char *kmap(KeySym, uint); +void cresize(int, int); +void selclear(void); + +void selinit(void); +void selnormalize(void); +int selected(int, int); +char *getsel(void); +int x2col(int); +int y2row(int); + +size_t utf8decode(char *, Rune *, size_t); +size_t utf8encode(Rune, char *); + +void *xmalloc(size_t); +char *xstrdup(char *); + +void usage(void); + +/* Globals */ +extern TermWindow win; +extern Term term; +extern Selection sel; +extern int cmdfd; +extern pid_t pid; +extern char **opt_cmd; +extern char *opt_class; +extern char *opt_embed; +extern char *opt_font; +extern char *opt_io; +extern char *opt_line; +extern char *opt_name; +extern char *opt_title; +extern int oldbutton; + +extern char *usedfont; +extern double usedfontsize; +extern double defaultfontsize; + +/* config.h globals */ +extern char font[]; +extern int borderpx; +extern float cwscale; +extern float chscale; +extern unsigned int doubleclicktimeout; +extern unsigned int tripleclicktimeout; +extern int allowaltscreen; +extern unsigned int xfps; +extern unsigned int actionfps; +extern unsigned int cursorthickness; +extern unsigned int blinktimeout; +extern char termname[]; +extern const char *colorname[]; +extern size_t colornamelen; +extern unsigned int defaultfg; +extern unsigned int defaultbg; +extern unsigned int defaultcs; +extern unsigned int defaultrcs; +extern unsigned int cursorshape; +extern unsigned int cols; +extern unsigned int rows; +extern unsigned int mouseshape; +extern unsigned int mousefg; +extern unsigned int mousebg; +extern unsigned int defaultattr; +extern MouseShortcut mshortcuts[]; +extern size_t mshortcutslen; +extern Shortcut shortcuts[]; +extern size_t shortcutslen; +extern uint forceselmod; +extern uint selmasks[]; +extern size_t selmaskslen; +extern char ascii_printable[]; diff --git a/win.h b/win.h new file mode 100644 index 0000000..d684797 --- /dev/null +++ b/win.h @@ -0,0 +1,29 @@ +/* See LICENSE for license details. */ + +/* X modifiers */ +#define XK_ANY_MOD UINT_MAX +#define XK_NO_MOD 0 +#define XK_SWITCH_MOD (1<<13) + +typedef XftGlyphFontSpec GlyphFontSpec; + +void draw(void); +void drawregion(int, int, int, int); +void run(void); + +void xbell(int); +void xclipcopy(void); +void xclippaste(void); +void xhints(void); +void xinit(void); +void xloadcols(void); +int xsetcolorname(int, const char *); +void xloadfonts(char *, double); +void xsetenv(void); +void xsettitle(char *); +void xsetpointermotion(int); +void xseturgency(int); +void xunloadfonts(void); +void xresize(int, int); +void xselpaste(void); +unsigned long xwinid(void); diff --git a/x.c b/x.c new file mode 100644 index 0000000..6474a01 --- /dev/null +++ b/x.c @@ -0,0 +1,1766 @@ +/* See LICENSE for license details. */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "arg.h" + +#define Glyph Glyph_ +#define Font Font_ + +#include "win.h" +#include "st.h" + +/* XEMBED messages */ +#define XEMBED_FOCUS_IN 4 +#define XEMBED_FOCUS_OUT 5 + +/* macros */ +#define TRUERED(x) (((x) & 0xff0000) >> 8) +#define TRUEGREEN(x) (((x) & 0xff00)) +#define TRUEBLUE(x) (((x) & 0xff) << 8) + +typedef XftDraw *Draw; +typedef XftColor Color; + +/* 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 */ +} XWindow; + +typedef struct { + Atom xtarget; +} XSelection; + +/* 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; + 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 void xdrawcursor(void); +static int xgeommasktogravity(int); +static int xloadfont(Font *, FcPattern *); +static void xsetsel(char *, Time); +static void xunloadfont(Font *); + +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 selcopy(Time); +static void getbuttoninfo(XEvent *); +static void mousereport(XEvent *); + +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; + +/* 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; + +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 < selmaskslen; ++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; + + if (IS_SET(MODE_MOUSE) && !(e->xbutton.state & forceselmod)) { + mousereport(e); + return; + } + + for (ms = mshortcuts; ms < mshortcuts + mshortcutslen; ms++) { + if (e->xbutton.button == ms->b + && match(ms->mask, e->xbutton.state)) { + ttysend(ms->s, strlen(ms->s)); + 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; + } +} + +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 +xselpaste(void) +{ + XConvertSelection(xw.dpy, XA_PRIMARY, xsel.xtarget, XA_PRIMARY, + xw.win, CurrentTime); +} + +void +xclipcopy(void) +{ + 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 +xclippaste(void) +{ + Atom clipboard; + + clipboard = XInternAtom(xw.dpy, "CLIPBOARD", 0); + XConvertSelection(xw.dpy, clipboard, xsel.xtarget, clipboard, + xw.win, CurrentTime); +} + +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 = 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_(NULL); +} + +void +brelease(XEvent *e) +{ + if (IS_SET(MODE_MOUSE) && !(e->xbutton.state & forceselmod)) { + mousereport(e); + return; + } + + if (e->xbutton.button == Button2) { + xselpaste(); + } 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 +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, + DefaultDepth(xw.dpy, xw.scr)); + XftDrawChange(xw.draw, xw.buf); + xclear(0, 0, win.w, win.h); +} + +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(colornamelen, 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); + } + 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; +} + +/* + * 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 = 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; + 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. */ + win.cw = ceilf(dc.font.width * cwscale); + win.ch = ceilf(dc.font.height * chscale); + + 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(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.vis = XDefaultVisual(xw.dpy, xw.scr); + + /* font */ + if (!FcInit()) + die("Could not init fontconfig.\n"); + + usedfont = (opt_font == NULL)? font : opt_font; + xloadfonts(usedfont, 0); + + /* colors */ + xw.cmap = XDefaultColormap(xw.dpy, xw.scr); + xloadcols(); + + /* adjust fixed window geometry */ + win.w = 2 * borderpx + term.col * win.cw; + win.h = 2 * borderpx + term.row * 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, XDefaultDepth(xw.dpy, xw.scr), 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)); + XSetForeground(xw.dpy, dc.gc, dc.col[defaultbg].pixel); + XFillRectangle(xw.dpy, xw.buf, dc.gc, 0, 0, win.w, win.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, 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); + + resettitle(); + XMapWindow(xw.dpy, xw.win); + xhints(); + XSync(xw.dpy, False); + + 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; 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; + } + + /* 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 * 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 + 8]; + + 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 + win.ch + ((y >= term.row-1)? win.h : 0)); + } + if (x + charlen >= term.col) { + xclear(winx + width, (y == 0)? 0 : winy, win.w, + ((y >= term.row-1)? win.h : (winy + win.ch))); + } + if (y == 0) + xclear(winx, 0, winx + width, borderpx); + if (y == term.row-1) + 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 + dc.font.ascent + 1, + width, 1); + } + + if (base.mode & ATTR_STRUCK) { + XftDrawRect(xw.draw, fg, winx, winy + 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 (win.state & WIN_FOCUSED) { + switch (win.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 * win.cw, + borderpx + (term.c.y + 1) * win.ch - \ + cursorthickness, + win.cw, cursorthickness); + break; + case 5: /* Blinking bar */ + case 6: /* Steady bar */ + XftDrawRect(xw.draw, &drawcol, + borderpx + curx * win.cw, + borderpx + term.c.y * win.ch, + cursorthickness, win.ch); + break; + } + } else { + XftDrawRect(xw.draw, &drawcol, + borderpx + curx * win.cw, + borderpx + term.c.y * win.ch, + win.cw - 1, 1); + XftDrawRect(xw.draw, &drawcol, + borderpx + curx * win.cw, + borderpx + term.c.y * win.ch, + 1, win.ch - 1); + XftDrawRect(xw.draw, &drawcol, + borderpx + (curx + 1) * win.cw - 1, + borderpx + term.c.y * win.ch, + 1, win.ch - 1); + XftDrawRect(xw.draw, &drawcol, + borderpx + curx * win.cw, + borderpx + (term.c.y + 1) * win.ch - 1, + win.cw, 1); + } + oldx = curx, oldy = term.c.y; +} + +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; + + 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 +draw(void) +{ + drawregion(0, 0, term.col, term.row); + 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 +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 (!(win.state & WIN_VISIBLE)) + return; + + for (y = y1; y < y2; y++) { + if (!term.dirty[y]) + continue; + + term.dirty[y] = 0; + + specs = term.specbuf; + numspecs = xmakeglyphfontspecs(specs, &term.line[y][x1], x2 - x1, x1, y); + + i = ox = 0; + for (x = x1; x < x2 && i < numspecs; x++) { + new = term.line[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); + } + xdrawcursor(); +} + +void +expose(XEvent *ev) +{ + redraw(); +} + +void +visibility(XEvent *ev) +{ + XVisibilityEvent *e = &ev->xvisibility; + + MODBIT(win.state, e->state != VisibilityFullyObscured, WIN_VISIBLE); +} + +void +unmap(XEvent *ev) +{ + win.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 +xbell(int vol) +{ + XkbBell(xw.dpy, xw.win, vol, (Atom)NULL); +} + +unsigned long +xwinid(void) +{ + return xw.win; +} + +void +focus(XEvent *ev) +{ + XFocusChangeEvent *e = &ev->xfocus; + + if (e->mode == NotifyGrab) + return; + + if (ev->type == FocusIn) { + XSetICFocus(xw.xic); + win.state |= WIN_FOCUSED; + xseturgency(0); + if (IS_SET(MODE_FOCUS)) + ttywrite("\033[I", 3); + } else { + XUnsetICFocus(xw.xic); + win.state &= ~WIN_FOCUSED; + if (IS_SET(MODE_FOCUS)) + ttywrite("\033[O", 3); + } +} + +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 + shortcutslen; 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) { + win.state |= WIN_FOCUSED; + xseturgency(0); + } else if (e->xclient.data.l[1] == XEMBED_FOCUS_OUT) { + win.state &= ~WIN_FOCUSED; + } + } else if (e->xclient.data.l[0] == xw.wmdeletewin) { + /* Send SIGHUP to shell */ + kill(pid, SIGHUP); + 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); + ttyresize(); +} + +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; + 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; + } + } + } + } +} + +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_line) + opt_title = basename(xstrdup(argv[0])); + } + setlocale(LC_CTYPE, ""); + XSetLocaleModifiers(""); + tnew(MAX(cols, 1), MAX(rows, 1)); + xinit(); + selinit(); + run(); + + return 0; +} From 20f713548de451b67db3306cf8cf7b2f38fee05c Mon Sep 17 00:00:00 2001 From: "Roberto E. Vargas Caballero" Date: Wed, 25 Jan 2017 19:17:38 +0100 Subject: [PATCH 003/129] Change default keybindings CTRL+SHIFT is an impossible combination in the terminal world (0x20 | x & 0x1F), so it is perfect to be used for internals shortcuts of terminals, and being a double combination reduces the prossibility of having comflicts. --- config.def.h | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/config.def.h b/config.def.h index fd80923..877afab 100644 --- a/config.def.h +++ b/config.def.h @@ -162,6 +162,7 @@ MouseShortcut mshortcuts[] = { /* Internal keyboard shortcuts. */ #define MODKEY Mod1Mask +#define TERMMOD (ControlMask|ShiftMask) Shortcut shortcuts[] = { /* mask keysym function argument */ @@ -169,15 +170,14 @@ 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, zoom, {.f = +1} }, - { MODKEY|ShiftMask, XK_Next, zoom, {.f = -1} }, - { MODKEY|ShiftMask, XK_Home, zoomreset, {.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} }, + { 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} }, }; /* From e7ed326d2e914a57017c9f34459824614075519b Mon Sep 17 00:00:00 2001 From: "osandov@osandov.com" Date: Sat, 18 Mar 2017 11:55:04 +0100 Subject: [PATCH 004/129] Support xterm Ms feature to set clipboard This is used by, e.g., tmux. --- st.c | 57 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ st.info | 1 + win.h | 1 + x.c | 1 - 4 files changed, 59 insertions(+), 1 deletion(-) diff --git a/st.c b/st.c index 1e4196e..d7bd32a 100644 --- a/st.c +++ b/st.c @@ -198,6 +198,8 @@ static char utf8encodebyte(Rune, size_t); static char *utf8strchr(char *s, Rune u); static size_t utf8validate(Rune *, size_t); +static char *base64dec(const char *); + static ssize_t xwrite(int, const char *, size_t); static void *xrealloc(void *, size_t); @@ -369,6 +371,48 @@ 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(const char *src) +{ + size_t in_len = strlen(src); + char *result, *dst; + + if (in_len % 4) + return NULL; + result = dst = xmalloc(in_len / 4 * 3 + 1); + while (*src) { + int a = base64_digits[(unsigned char) *src++]; + int b = base64_digits[(unsigned char) *src++]; + int c = base64_digits[(unsigned char) *src++]; + int d = base64_digits[(unsigned char) *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) { @@ -1820,6 +1864,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, CurrentTime); + clipcopy(NULL); + } else { + fprintf(stderr, "erresc: invalid base64\n"); + } + } + return; case 4: /* color set */ if (narg < 3) break; diff --git a/st.info b/st.info index 13cc8eb..0b928af 100644 --- a/st.info +++ b/st.info @@ -189,6 +189,7 @@ st| simpleterm, Se, Ss, Tc, + Ms=\E]52;%p1%s;%p2%s\007, st-256color| simpleterm with 256 colors, use=st, diff --git a/win.h b/win.h index d684797..428111c 100644 --- a/win.h +++ b/win.h @@ -27,3 +27,4 @@ void xunloadfonts(void); void xresize(int, int); void xselpaste(void); unsigned long xwinid(void); +void xsetsel(char *, Time); diff --git a/x.c b/x.c index 6474a01..743b084 100644 --- a/x.c +++ b/x.c @@ -88,7 +88,6 @@ static void xclear(int, int, int, int); static void xdrawcursor(void); static int xgeommasktogravity(int); static int xloadfont(Font *, FcPattern *); -static void xsetsel(char *, Time); static void xunloadfont(Font *); static void expose(XEvent *); From f2bfd513b14a2aa27796670235557a550b4189db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nils=20Reu=C3=9Fe?= Date: Wed, 29 Mar 2017 18:34:12 +0200 Subject: [PATCH 005/129] keep some glyph modes for the cursor st currently does not keep any mode for the cursor that was active in the underlying glyph (e.g. italic text), the mode is always ATTR_NULL [1]. At [2] you can find a screenshot that shows the implications. Other terminals (at least vte-based, such as XFCE-terminal) keep some modes for the cursor. I find the current behaviour very disruptive, so here is a patch that keeps a few (arbitrarily chosen) modes for the cursor. [1] http://git.suckless.org/st/tree/st.c#n3963 [2] http://i.imgur.com/R2yCEaC.png --- x.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/x.c b/x.c index 743b084..b7339e9 100644 --- a/x.c +++ b/x.c @@ -1266,6 +1266,7 @@ xdrawcursor(void) Glyph g = {' ', ATTR_NULL, defaultbg, defaultcs}, og; int ena_sel = sel.ob.x != -1 && sel.alt == IS_SET(MODE_ALTSCREEN); Color drawcol; + unsigned attr; LIMIT(oldx, 0, term.col-1); LIMIT(oldy, 0, term.row-1); @@ -1285,6 +1286,8 @@ xdrawcursor(void) xdrawglyph(og, oldx, oldy); g.u = term.line[term.c.y][term.c.x].u; + attr = ATTR_BOLD | ATTR_ITALIC | ATTR_UNDERLINE | ATTR_STRUCK; + g.mode |= term.line[term.c.y][term.c.x].mode & attr; /* * Select the right color for the right mode. From 149c0d3aedffe69b625ef95868daae200941d5f5 Mon Sep 17 00:00:00 2001 From: Alexander Krotov Date: Sat, 25 Mar 2017 23:02:42 +0300 Subject: [PATCH 006/129] Fix commented out code --- st.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/st.c b/st.c index d7bd32a..ae93ade 100644 --- a/st.c +++ b/st.c @@ -2537,7 +2537,7 @@ tresize(int col, int row) } /* 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)); } From 745c40f8b07ab898d1f9d4f564881b40599bc80d Mon Sep 17 00:00:00 2001 From: Quentin Rameau Date: Tue, 4 Apr 2017 17:20:55 +0200 Subject: [PATCH 007/129] Simplify how we keep ATTRs under cursor Thanks to tarug0 for the suggestion/patch. --- x.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/x.c b/x.c index b7339e9..fbfd350 100644 --- a/x.c +++ b/x.c @@ -1266,7 +1266,6 @@ xdrawcursor(void) Glyph g = {' ', ATTR_NULL, defaultbg, defaultcs}, og; int ena_sel = sel.ob.x != -1 && sel.alt == IS_SET(MODE_ALTSCREEN); Color drawcol; - unsigned attr; LIMIT(oldx, 0, term.col-1); LIMIT(oldy, 0, term.row-1); @@ -1286,8 +1285,8 @@ xdrawcursor(void) xdrawglyph(og, oldx, oldy); g.u = term.line[term.c.y][term.c.x].u; - attr = ATTR_BOLD | ATTR_ITALIC | ATTR_UNDERLINE | ATTR_STRUCK; - g.mode |= term.line[term.c.y][term.c.x].mode & attr; + g.mode |= term.line[term.c.y][term.c.x].mode & + (ATTR_BOLD | ATTR_ITALIC | ATTR_UNDERLINE | ATTR_STRUCK); /* * Select the right color for the right mode. From 5a10aca702bf7bc9094cb4abaea6c59558740d29 Mon Sep 17 00:00:00 2001 From: "greg.reagle@umbc.edu" Date: Mon, 10 Apr 2017 18:24:03 +0200 Subject: [PATCH 008/129] st.1: modify man page to accurately reflect default keybindings Attached. ===> 2/ (text/x-patch) [file] cp /mail/fs/mbox/298/2/body /usr/k0ga/0001-st.1-modify-man-page-to-accurately-reflect-default-k.patch From 265db94b1eca5850d484f86b7db4af8e57822cfe Mon Sep 17 00:00:00 2001 From: Greg Reagle Date: Sun, 9 Apr 2017 23:05:47 -0400 Subject: [PATCH] st.1: modify man page to accurately reflect default keybindings --- st.1 | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/st.1 b/st.1 index c429dcf..bbca7e5 100644 --- a/st.1 +++ b/st.1 @@ -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 From 6cb6d61525931c88971cce323f63e40451a6d365 Mon Sep 17 00:00:00 2001 From: Quentin Rameau Date: Sun, 28 May 2017 09:56:57 +0200 Subject: [PATCH 009/129] Add bold off SGR --- st.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/st.c b/st.c index ae93ade..8d4a9f2 100644 --- a/st.c +++ b/st.c @@ -1402,6 +1402,9 @@ tsetattr(int *attr, int l) case 9: term.c.attr.mode |= ATTR_STRUCK; break; + case 21: + term.c.attr.mode &= ~ATTR_BOLD; + break; case 22: term.c.attr.mode &= ~(ATTR_BOLD | ATTR_FAINT); break; From b331da550b290d54592b7ba11242c92f5a303a48 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc=20Andr=C3=A9=20Tanner?= Date: Mon, 15 May 2017 12:45:41 +0200 Subject: [PATCH 010/129] Add color change terminfo capabilities --- st.info | 3 +++ 1 file changed, 3 insertions(+) diff --git a/st.info b/st.info index 0b928af..4d77eae 100644 --- a/st.info +++ b/st.info @@ -193,9 +193,12 @@ st| simpleterm, 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, From fabd4602b3223666165c76c397644a081b9a97e5 Mon Sep 17 00:00:00 2001 From: Quentin Rameau Date: Wed, 12 Jul 2017 00:24:51 +0200 Subject: [PATCH 011/129] Do not obfuscate what make is doing. Change some styling too while we're at it. --- Makefile | 58 ++++++++++++++++++++++++------------------------------- config.mk | 16 +++++++-------- 2 files changed, 33 insertions(+), 41 deletions(-) diff --git a/Makefile b/Makefile index d8595fe..f5b84a0 100644 --- a/Makefile +++ b/Makefile @@ -1,63 +1,55 @@ # st - simple terminal # See LICENSE file for copyright and license details. +.POSIX: include config.mk SRC = st.c x.c -OBJ = ${SRC:.c=.o} +OBJ = $(SRC:.c=.o) all: options st options: @echo st build options: - @echo "CFLAGS = ${CFLAGS}" - @echo "LDFLAGS = ${LDFLAGS}" - @echo "CC = ${CC}" + @echo "CFLAGS = $(CFLAGS)" + @echo "LDFLAGS = $(LDFLAGS)" + @echo "CC = $(CC)" config.h: cp config.def.h config.h .c.o: - @echo CC $< - @${CC} -c ${CFLAGS} $< + $(CC) $(CFLAGS) -c $< st.o: config.h st.h win.h x.o: arg.h st.h win.h -${OBJ}: config.h config.mk +$(OBJ): config.h config.mk -st: ${OBJ} - @echo CC -o $@ - @${CC} -o $@ ${OBJ} ${LDFLAGS} +st: $(OBJ) + $(CC) $(LDFLAGS) -o $@ $(OBJ) clean: - @echo cleaning - @rm -f 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 LICENSE Makefile README config.mk config.def.h st.info st.1 arg.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/config.mk b/config.mk index c84c5ee..527a64d 100644 --- a/config.mk +++ b/config.mk @@ -5,24 +5,24 @@ VERSION = 0.7 # 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 -lXft \ - `pkg-config --libs fontconfig` \ +LIBS = -L$(X11LIB) -lm -lrt -lX11 -lutil -lXft \ + `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 +CFLAGS = -g -std=c99 -pedantic -Wall -Wvariadic-macros -Os $(INCS) $(CPPFLAGS) +LDFLAGS = -g $(LIBS) # compiler and linker -# CC = cc +# CC = c99 From d4928edba0fe2cc63b3bc13fd6dad0bcb875174e Mon Sep 17 00:00:00 2001 From: Quentin Rameau Date: Wed, 12 Jul 2017 00:26:35 +0200 Subject: [PATCH 012/129] Let the user specify C and LD FLAGS --- Makefile | 8 ++++---- config.mk | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Makefile b/Makefile index f5b84a0..128ee9d 100644 --- a/Makefile +++ b/Makefile @@ -11,15 +11,15 @@ all: options st options: @echo st build options: - @echo "CFLAGS = $(CFLAGS)" - @echo "LDFLAGS = $(LDFLAGS)" + @echo "CFLAGS = $(STCFLAGS)" + @echo "LDFLAGS = $(STLDFLAGS)" @echo "CC = $(CC)" config.h: cp config.def.h config.h .c.o: - $(CC) $(CFLAGS) -c $< + $(CC) $(STCFLAGS) -c $< st.o: config.h st.h win.h x.o: arg.h st.h win.h @@ -27,7 +27,7 @@ x.o: arg.h st.h win.h $(OBJ): config.h config.mk st: $(OBJ) - $(CC) $(LDFLAGS) -o $@ $(OBJ) + $(CC) $(STLDFLAGS) -o $@ $(OBJ) clean: rm -f st $(OBJ) st-$(VERSION).tar.gz diff --git a/config.mk b/config.mk index 527a64d..0aceec4 100644 --- a/config.mk +++ b/config.mk @@ -20,8 +20,8 @@ LIBS = -L$(X11LIB) -lm -lrt -lX11 -lutil -lXft \ # flags CPPFLAGS = -DVERSION=\"$(VERSION)\" -D_XOPEN_SOURCE=600 -CFLAGS = -g -std=c99 -pedantic -Wall -Wvariadic-macros -Os $(INCS) $(CPPFLAGS) -LDFLAGS = -g $(LIBS) +STCFLAGS = $(INCS) $(CPPFLAGS) $(CFLAGS) +STLDFLAGS = $(LIBS) $(LDFLAGS) # compiler and linker # CC = c99 From c0882f2ed1d7a2dd0fa2efa52157e6fc6fde3652 Mon Sep 17 00:00:00 2001 From: Quentin Rameau Date: Tue, 11 Jul 2017 23:03:27 +0200 Subject: [PATCH 013/129] Add dim/smxx/rmxx to terminfo, remove duplicate kich1 --- st.info | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/st.info b/st.info index 4d77eae..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,7 +185,10 @@ 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, From 8dacdfbab1c476063a31bc3b8d7222ac2b70ff66 Mon Sep 17 00:00:00 2001 From: Quentin Rameau Date: Tue, 11 Jul 2017 23:16:25 +0200 Subject: [PATCH 014/129] Revert "Add bold off SGR" This reverts commit 6cb6d61525931c88971cce323f63e40451a6d365. This wasn't a useful thing after all. --- st.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/st.c b/st.c index 8d4a9f2..ae93ade 100644 --- a/st.c +++ b/st.c @@ -1402,9 +1402,6 @@ tsetattr(int *attr, int l) case 9: term.c.attr.mode |= ATTR_STRUCK; break; - case 21: - term.c.attr.mode &= ~ATTR_BOLD; - break; case 22: term.c.attr.mode &= ~(ATTR_BOLD | ATTR_FAINT); break; From 7f990328e4fec8dfaaad311cb8af2304b58c872e Mon Sep 17 00:00:00 2001 From: Anselm R Garbe Date: Sun, 23 Jul 2017 11:17:26 +0200 Subject: [PATCH 015/129] fixed STLDFLAG order in broken st Makefile --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 128ee9d..c678ead 100644 --- a/Makefile +++ b/Makefile @@ -27,7 +27,7 @@ x.o: arg.h st.h win.h $(OBJ): config.h config.mk st: $(OBJ) - $(CC) $(STLDFLAGS) -o $@ $(OBJ) + $(CC) -o $@ $(OBJ) $(STLDFLAGS) clean: rm -f st $(OBJ) st-$(VERSION).tar.gz From 77c51c5a6b16387f1792e23acbcf2080f790aa25 Mon Sep 17 00:00:00 2001 From: Anselm R Garbe Date: Fri, 1 Sep 2017 09:48:24 +0200 Subject: [PATCH 016/129] make clipboard patch obsolete --- x.c | 1 + 1 file changed, 1 insertion(+) diff --git a/x.c b/x.c index fbfd350..ab9593e 100644 --- a/x.c +++ b/x.c @@ -507,6 +507,7 @@ xsetsel(char *str, Time t) XSetSelectionOwner(xw.dpy, XA_PRIMARY, xw.win, t); if (XGetSelectionOwner(xw.dpy, XA_PRIMARY) != xw.win) selclear_(NULL); + xclipcopy(); } void From 9c61f29bb7da237907e42875ebe7d0084e8ab1ac Mon Sep 17 00:00:00 2001 From: Hiltjo Posthuma Date: Sat, 2 Sep 2017 13:52:33 +0200 Subject: [PATCH 017/129] Revert "make clipboard patch obsolete" This reverts commit 77c51c5a6b16387f1792e23acbcf2080f790aa25. Having multiple clipboards are useful, for example for plumber scripts. I've discussed this on IRC and it is useful to have. --- x.c | 1 - 1 file changed, 1 deletion(-) diff --git a/x.c b/x.c index ab9593e..fbfd350 100644 --- a/x.c +++ b/x.c @@ -507,7 +507,6 @@ xsetsel(char *str, Time t) XSetSelectionOwner(xw.dpy, XA_PRIMARY, xw.win, t); if (XGetSelectionOwner(xw.dpy, XA_PRIMARY) != xw.win) selclear_(NULL); - xclipcopy(); } void From 274d46ace00003d1df718b974d17642cbce167d5 Mon Sep 17 00:00:00 2001 From: Hiltjo Posthuma Date: Wed, 13 Sep 2017 22:40:36 +0200 Subject: [PATCH 018/129] Revert "fixed STLDFLAG order in broken st Makefile" This reverts commit 7f990328e4fec8dfaaad311cb8af2304b58c872e. this was wrong as pointed out by k0ga: "STLDFLAGS is about flags to the linker, for example -L not about -l for that reason it must go before the object list". --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index c678ead..128ee9d 100644 --- a/Makefile +++ b/Makefile @@ -27,7 +27,7 @@ x.o: arg.h st.h win.h $(OBJ): config.h config.mk st: $(OBJ) - $(CC) -o $@ $(OBJ) $(STLDFLAGS) + $(CC) $(STLDFLAGS) -o $@ $(OBJ) clean: rm -f st $(OBJ) st-$(VERSION).tar.gz From ee5cc8e903574bf629e5159334ae6b0fad6af402 Mon Sep 17 00:00:00 2001 From: "Suraj N. Kurapati" Date: Thu, 17 Aug 2017 23:00:10 -0700 Subject: [PATCH 019/129] base64dec: skip non-printable characters like \r\n Non-printable characters, such as line breaks, in a base64 encoded string violate the "string length must be a multiple of four" rule. This patch pads the result buffer by one extra unit of four bytes, and skips over non-printable characters found in the input string. --- st.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/st.c b/st.c index ae93ade..7c7ddff 100644 --- a/st.c +++ b/st.c @@ -386,6 +386,13 @@ static const char base64_digits[] = { 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) { @@ -393,13 +400,13 @@ base64dec(const char *src) char *result, *dst; if (in_len % 4) - return NULL; + in_len += 4 - (in_len % 4); result = dst = xmalloc(in_len / 4 * 3 + 1); while (*src) { - int a = base64_digits[(unsigned char) *src++]; - int b = base64_digits[(unsigned char) *src++]; - int c = base64_digits[(unsigned char) *src++]; - int d = base64_digits[(unsigned char) *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) From b2ac91775302fa4b8ce462a6e7bcfffa93923471 Mon Sep 17 00:00:00 2001 From: Hiltjo Posthuma Date: Fri, 15 Sep 2017 11:16:37 +0200 Subject: [PATCH 020/129] Revert "Revert "fixed STLDFLAG order in broken st Makefile"" This reverts commit 274d46ace00003d1df718b974d17642cbce167d5. Sorry, the original commit was correct after all. It allows has the correct link order and supports static-linking also. Just a reminder: it is important to give a (brief) rationale of the patch intentions. --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 128ee9d..c678ead 100644 --- a/Makefile +++ b/Makefile @@ -27,7 +27,7 @@ x.o: arg.h st.h win.h $(OBJ): config.h config.mk st: $(OBJ) - $(CC) $(STLDFLAGS) -o $@ $(OBJ) + $(CC) -o $@ $(OBJ) $(STLDFLAGS) clean: rm -f st $(OBJ) st-$(VERSION).tar.gz From b1338e91ed632adbcd08388de37e46cf25326e01 Mon Sep 17 00:00:00 2001 From: Gary Allen Vollink Date: Thu, 14 Sep 2017 15:30:02 -0400 Subject: [PATCH 021/129] Add an error for XftFontOpenPattern failure. --- x.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/x.c b/x.c index fbfd350..191e5dc 100644 --- a/x.c +++ b/x.c @@ -1092,6 +1092,9 @@ xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x 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; From 0ac685fc015362e749bf82cfaa3cfe2dd9b305f0 Mon Sep 17 00:00:00 2001 From: Paride Legovini Date: Tue, 10 Oct 2017 17:49:38 +0200 Subject: [PATCH 022/129] Fix manpage typo Signed-off-by: Paride Legovini --- st.1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/st.1 b/st.1 index bbca7e5..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 From c1d23afa9c44cc29818c538126790ae90a64a3c5 Mon Sep 17 00:00:00 2001 From: George Ornbo Date: Wed, 20 Dec 2017 09:05:32 +0000 Subject: [PATCH 023/129] Fix FAQ typo --- FAQ | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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! From e829e13bb1a830e0cdce749ea0865cd93af1846c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benno=20F=C3=BCnfst=C3=BCck?= Date: Tue, 26 Dec 2017 16:38:27 +0100 Subject: [PATCH 024/129] Apply ATTR_REVERSE after ATTR_FAINT An example where the new behaviour makes more sense: Suppose some text is formatted with ATTR_FAINT for red for the foreground, so it is rendered in a dark red. In that case, when selected with the mouse, the intended behaviour is that foreground and background color are swapped: so the selection should be rendered in dark red and the text in the default background color. Before this patch, what happened was that the selection would be in normal red and the text in the darkened background color, making it almost unreadable. For an example application that uses the FAINT attribute, try dmesg from util-linux with color support, it uses FAINT for segfault messages. --- x.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/x.c b/x.c index 191e5dc..474d73b 100644 --- a/x.c +++ b/x.c @@ -1189,12 +1189,6 @@ xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, i } } - 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; @@ -1203,6 +1197,13 @@ xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, i fg = &revfg; } + + if (base.mode & ATTR_REVERSE) { + temp = fg; + fg = bg; + bg = temp; + } + if (base.mode & ATTR_BLINK && term.mode & MODE_BLINK) fg = bg; From 1f24bde82b19912c080fbb4a0b153a248cd6c6ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benno=20F=C3=BCnfst=C3=BCck?= Date: Tue, 26 Dec 2017 16:23:24 +0100 Subject: [PATCH 025/129] Fix color with FAINT attribute The alpha value needs to be initialized as well. --- x.c | 1 + 1 file changed, 1 insertion(+) diff --git a/x.c b/x.c index 474d73b..c484dfc 100644 --- a/x.c +++ b/x.c @@ -1193,6 +1193,7 @@ xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, i 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; } From 65976c1a29f2945c3cfb6af74cd6440cf193021d Mon Sep 17 00:00:00 2001 From: "Devin J. Pohly" Date: Tue, 17 Oct 2017 15:21:04 -0500 Subject: [PATCH 026/129] Move config.h include from st.c to x.c config.h includes references to KeySyms and other X stuff. Until we come up with a cleaner way to separate configuration, it is simpler (leads to more code removal) to have this here. Signed-off-by: Devin J. Pohly --- config.def.h | 73 ++++++++++++++++++++++++++-------------------------- st.c | 47 +++------------------------------ st.h | 50 ++++++++++------------------------- win.h | 3 --- x.c | 37 ++++++++++++++++++++++++++ 5 files changed, 91 insertions(+), 119 deletions(-) diff --git a/config.def.h b/config.def.h index 18cb31c..1c181ab 100644 --- a/config.def.h +++ b/config.def.h @@ -5,8 +5,8 @@ * * font: see http://freedesktop.org/software/fontconfig/fontconfig-user.html */ -char font[] = "Liberation Mono:pixelsize=12:antialias=true:autohint=true"; -int borderpx = 2; +static char *font = "Liberation Mono:pixelsize=12:antialias=true:autohint=true"; +static int borderpx = 2; /* * What program is execed by st depends of these precedence rules: @@ -16,54 +16,54 @@ 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"; +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 */ -float cwscale = 1.0; -float chscale = 1.0; +static float cwscale = 1.0; +static float chscale = 1.0; /* * word delimiter string * * More advanced example: " `'\"()[]{}" */ -static char worddelimiters[] = " "; +char *worddelimiters = " "; /* selection timeouts (in milliseconds) */ -unsigned int doubleclicktimeout = 300; -unsigned int tripleclicktimeout = 600; +static unsigned int doubleclicktimeout = 300; +static unsigned int tripleclicktimeout = 600; /* alt screens */ int allowaltscreen = 1; /* frames per second st should at maximum draw to the screen */ -unsigned int xfps = 120; -unsigned int actionfps = 30; +static unsigned int xfps = 120; +static unsigned int actionfps = 30; /* * blinking timeout (set to 0 to disable blinking) for the terminal blinking * attribute. */ -unsigned int blinktimeout = 800; +static unsigned int blinktimeout = 800; /* * thickness of underline and bar cursors */ -unsigned int cursorthickness = 2; +static unsigned int cursorthickness = 2; /* * bell volume. It must be a value between -100 and 100. Use 0 for disabling * it */ -int bellvolume = 0; +static int bellvolume = 0; /* default TERM value */ -char termname[] = "st-256color"; +char *termname = "st-256color"; /* * spaces per tab @@ -80,10 +80,10 @@ char termname[] = "st-256color"; * * stty tabs */ -static unsigned int tabspaces = 8; +unsigned int tabspaces = 8; /* Terminal colors (16 first used in escape sequence) */ -const char *colorname[] = { +static const char *colorname[] = { /* 8 normal colors */ "black", "red3", @@ -118,8 +118,8 @@ const char *colorname[] = { */ unsigned int defaultfg = 7; unsigned int defaultbg = 0; -unsigned int defaultcs = 256; -unsigned int defaultrcs = 257; +static unsigned int defaultcs = 256; +static unsigned int defaultrcs = 257; /* * Default shape of cursor @@ -128,33 +128,33 @@ unsigned int defaultrcs = 257; * 6: Bar ("|") * 7: Snowman ("☃") */ -unsigned int cursorshape = 2; +static unsigned int cursorshape = 2; /* * Default columns and rows numbers */ -unsigned int cols = 80; -unsigned int rows = 24; +static unsigned int cols = 80; +static unsigned int rows = 24; /* * Default colour and shape of the mouse cursor */ -unsigned int mouseshape = XC_xterm; -unsigned int mousefg = 7; -unsigned int mousebg = 0; +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. */ -unsigned int defaultattr = 11; +static unsigned int defaultattr = 11; /* * Internal mouse shortcuts. * Beware that overloading Button1 will disable the selection. */ -MouseShortcut mshortcuts[] = { +static MouseShortcut mshortcuts[] = { /* button mask string */ { Button4, XK_ANY_MOD, "\031" }, { Button5, XK_ANY_MOD, "\005" }, @@ -164,7 +164,7 @@ MouseShortcut mshortcuts[] = { #define MODKEY Mod1Mask #define TERMMOD (ControlMask|ShiftMask) -Shortcut shortcuts[] = { +static Shortcut shortcuts[] = { /* mask keysym function argument */ { XK_ANY_MOD, XK_Break, sendbreak, {.i = 0} }, { ControlMask, XK_Print, toggleprinter, {.i = 0} }, @@ -209,26 +209,26 @@ Shortcut shortcuts[] = { * If you want keys other than the X11 function keys (0xFD00 - 0xFFFF) * to be mapped below, add them to this array. */ -KeySym mappedkeys[] = { -1 }; +static KeySym mappedkeys[] = { -1 }; /* * State bits to ignore when matching key or button events. By default, * numlock (Mod2Mask) and keyboard layout (XK_SWITCH_MOD) are ignored. */ -uint ignoremod = Mod2Mask|XK_SWITCH_MOD; +static uint ignoremod = Mod2Mask|XK_SWITCH_MOD; /* * Override mouse-select while mask is active (when MODE_MOUSE is set). * Note that if you want to use ShiftMask with selmasks, set this to an other * modifier, set to 0 to not use it. */ -uint forceselmod = ShiftMask; +static uint forceselmod = ShiftMask; /* * This is the huge key array which defines all compatibility to the Linux * world. Please decide about changes wisely. */ -Key key[] = { +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}, @@ -451,7 +451,7 @@ Key key[] = { * ButtonRelease and MotionNotify. * If no match is found, regular selection is used. */ -uint selmasks[] = { +static uint selmasks[] = { [SEL_RECTANGULAR] = Mod1Mask, }; @@ -459,8 +459,7 @@ uint selmasks[] = { * Printable characters in ASCII, used to estimate the advance width * of single wide characters. */ -char ascii_printable[] = +static char ascii_printable[] = " !\"#$%&'()*+,-./0123456789:;<=>?" "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_" "`abcdefghijklmnopqrstuvwxyz{|}~"; - diff --git a/st.c b/st.c index 641f896..ec747cc 100644 --- a/st.c +++ b/st.c @@ -109,19 +109,6 @@ typedef struct { int narg; /* nb of args */ } STREscape; -/* 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 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" static void execsh(char **); static void stty(char **); @@ -199,14 +186,6 @@ 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}; -/* config.h array lengths */ -size_t colornamelen = LEN(colorname); -size_t mshortcutslen = LEN(mshortcuts); -size_t shortcutslen = LEN(shortcuts); -size_t selmaskslen = LEN(selmasks); -size_t keyslen = LEN(key); -size_t mappedkeyslen = LEN(mappedkeys); - ssize_t xwrite(int fd, const char *s, size_t len) { @@ -585,24 +564,6 @@ getsel(void) return str; } -void -selpaste(const Arg *dummy) -{ - xselpaste(); -} - -void -clipcopy(const Arg *dummy) -{ - xclipcopy(); -} - -void -clippaste(const Arg *dummy) -{ - xclippaste(); -} - void selclear(void) { @@ -1572,7 +1533,7 @@ csihandle(void) break; case 'c': /* DA -- Device Attributes */ if (csiescseq.arg[0] == 0) - ttywrite(vtiden, sizeof(vtiden) - 1); + ttywrite(vtiden, strlen(vtiden)); break; case 'C': /* CUF -- Cursor Forward */ case 'a': /* HPR -- Cursor Forward */ @@ -1791,7 +1752,7 @@ strhandle(void) dec = base64dec(strescseq.args[2]); if (dec) { xsetsel(dec, CurrentTime); - clipcopy(NULL); + xclipcopy(); } else { fprintf(stderr, "erresc: invalid base64\n"); } @@ -2134,7 +2095,7 @@ tcontrolcode(uchar ascii) case 0x99: /* TODO: SGCI */ break; case 0x9a: /* DECID -- Identify Terminal */ - ttywrite(vtiden, sizeof(vtiden) - 1); + ttywrite(vtiden, strlen(vtiden)); break; case 0x9b: /* TODO: CSI */ case 0x9c: /* TODO: ST */ @@ -2206,7 +2167,7 @@ eschandle(uchar ascii) } break; case 'Z': /* DECID -- Identify Terminal */ - ttywrite(vtiden, sizeof(vtiden) - 1); + ttywrite(vtiden, strlen(vtiden)); break; case 'c': /* RIS -- Reset to inital state */ treset(); diff --git a/st.h b/st.h index 3d9b6e7..9314607 100644 --- a/st.h +++ b/st.h @@ -190,6 +190,13 @@ typedef struct { void die(const char *, ...); void redraw(void); +void iso14755(const Arg *); +void numlock(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); @@ -225,42 +232,13 @@ extern pid_t pid; extern int oldbutton; /* config.h globals */ -extern char font[]; -extern int borderpx; -extern float cwscale; -extern float chscale; -extern unsigned int doubleclicktimeout; -extern unsigned int tripleclicktimeout; +extern char *shell; +extern char *utmp; +extern char *stty_args; +extern char *vtiden; +extern char *worddelimiters; extern int allowaltscreen; -extern unsigned int xfps; -extern unsigned int actionfps; -extern unsigned int cursorthickness; -extern int bellvolume; -extern unsigned int blinktimeout; -extern char termname[]; -extern const char *colorname[]; -extern size_t colornamelen; +extern char *termname; +extern unsigned int tabspaces; extern unsigned int defaultfg; extern unsigned int defaultbg; -extern unsigned int defaultcs; -extern unsigned int defaultrcs; -extern unsigned int cursorshape; -extern unsigned int cols; -extern unsigned int rows; -extern unsigned int mouseshape; -extern unsigned int mousefg; -extern unsigned int mousebg; -extern unsigned int defaultattr; -extern MouseShortcut mshortcuts[]; -extern size_t mshortcutslen; -extern Shortcut shortcuts[]; -extern size_t shortcutslen; -extern KeySym mappedkeys[]; -extern size_t mappedkeyslen; -extern uint ignoremod; -extern uint forceselmod; -extern Key key[]; -extern size_t keyslen; -extern uint selmasks[]; -extern size_t selmaskslen; -extern char ascii_printable[]; diff --git a/win.h b/win.h index 00113c5..b7022ec 100644 --- a/win.h +++ b/win.h @@ -18,6 +18,3 @@ void xsettitle(char *); void xsetpointermotion(int); void xselpaste(void); void xsetsel(char *, Time); -void zoom(const Arg *); -void zoomabs(const Arg *); -void zoomreset(const Arg *); diff --git a/x.c b/x.c index e267961..cb8c351 100644 --- a/x.c +++ b/x.c @@ -20,6 +20,25 @@ static char *argv0; #include "st.h" #include "win.h" +/* function definitions used in config.h */ +static void clipcopy(const Arg *); +static void clippaste(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" + +/* config.h array lengths */ +size_t colornamelen = LEN(colorname); +size_t mshortcutslen = LEN(mshortcuts); +size_t shortcutslen = LEN(shortcuts); +size_t selmaskslen = LEN(selmasks); +size_t keyslen = LEN(key); +size_t mappedkeyslen = LEN(mappedkeys); + /* XEMBED messages */ #define XEMBED_FOCUS_IN 4 #define XEMBED_FOCUS_OUT 5 @@ -188,6 +207,24 @@ static char *opt_line = NULL; static char *opt_name = NULL; static char *opt_title = NULL; +void +clipcopy(const Arg *dummy) +{ + xclipcopy(); +} + +void +clippaste(const Arg *dummy) +{ + xclippaste(); +} + +void +selpaste(const Arg *dummy) +{ + xselpaste(); +} + void zoom(const Arg *arg) { From 428f01969aaf48ffa2983746c0a397bcc8946799 Mon Sep 17 00:00:00 2001 From: "Devin J. Pohly" Date: Tue, 17 Oct 2017 15:43:32 -0500 Subject: [PATCH 027/129] Inline clipboard functions No need to keep a function that only calls another function in the same file. Signed-off-by: Devin J. Pohly --- win.h | 2 -- x.c | 50 +++++++++++++++++++------------------------------- 2 files changed, 19 insertions(+), 33 deletions(-) diff --git a/win.h b/win.h index b7022ec..beb458d 100644 --- a/win.h +++ b/win.h @@ -10,11 +10,9 @@ void drawregion(int, int, int, int); void xbell(void); void xclipcopy(void); -void xclippaste(void); void xhints(void); void xloadcols(void); int xsetcolorname(int, const char *); void xsettitle(char *); void xsetpointermotion(int); -void xselpaste(void); void xsetsel(char *, Time); diff --git a/x.c b/x.c index cb8c351..46356fe 100644 --- a/x.c +++ b/x.c @@ -210,19 +210,33 @@ static char *opt_title = NULL; void clipcopy(const Arg *dummy) { - xclipcopy(); + 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) { - xclippaste(); + Atom clipboard; + + clipboard = XInternAtom(xw.dpy, "CLIPBOARD", 0); + XConvertSelection(xw.dpy, clipboard, xsel.xtarget, clipboard, + xw.win, CurrentTime); } void selpaste(const Arg *dummy) { - xselpaste(); + XConvertSelection(xw.dpy, XA_PRIMARY, xsel.xtarget, XA_PRIMARY, + xw.win, CurrentTime); } void @@ -518,36 +532,10 @@ selnotify(XEvent *e) XDeleteProperty(xw.dpy, xw.win, (int)property); } -void -xselpaste(void) -{ - XConvertSelection(xw.dpy, XA_PRIMARY, xsel.xtarget, XA_PRIMARY, - xw.win, CurrentTime); -} - void xclipcopy(void) { - 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 -xclippaste(void) -{ - Atom clipboard; - - clipboard = XInternAtom(xw.dpy, "CLIPBOARD", 0); - XConvertSelection(xw.dpy, clipboard, xsel.xtarget, clipboard, - xw.win, CurrentTime); + clipcopy(NULL); } void @@ -634,7 +622,7 @@ brelease(XEvent *e) } if (e->xbutton.button == Button2) { - xselpaste(); + selpaste(NULL); } else if (e->xbutton.button == Button1) { if (sel.mode == SEL_READY) { getbuttoninfo(e); From 75c9a0ee1d232a1a177746d97a13cf92b03da44a Mon Sep 17 00:00:00 2001 From: "Devin J. Pohly" Date: Tue, 17 Oct 2017 15:46:31 -0500 Subject: [PATCH 028/129] Remove unneeded array-length variables These were only used in x.c, which now has direct visibility of the config.h arrays. Signed-off-by: Devin J. Pohly --- x.c | 22 +++++++--------------- 1 file changed, 7 insertions(+), 15 deletions(-) diff --git a/x.c b/x.c index 46356fe..03555d1 100644 --- a/x.c +++ b/x.c @@ -31,14 +31,6 @@ static void zoomreset(const Arg *); /* config.h for applying patches and the configuration. */ #include "config.h" -/* config.h array lengths */ -size_t colornamelen = LEN(colorname); -size_t mshortcutslen = LEN(mshortcuts); -size_t shortcutslen = LEN(shortcuts); -size_t selmaskslen = LEN(selmasks); -size_t keyslen = LEN(key); -size_t mappedkeyslen = LEN(mappedkeys); - /* XEMBED messages */ #define XEMBED_FOCUS_IN 4 #define XEMBED_FOCUS_OUT 5 @@ -301,7 +293,7 @@ getbuttoninfo(XEvent *e) selnormalize(); sel.type = SEL_REGULAR; - for (type = 1; type < selmaskslen; ++type) { + for (type = 1; type < LEN(selmasks); ++type) { if (match(selmasks[type], state)) { sel.type = type; break; @@ -384,7 +376,7 @@ bpress(XEvent *e) return; } - for (ms = mshortcuts; ms < mshortcuts + mshortcutslen; ms++) { + 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)); @@ -728,7 +720,7 @@ xloadcols(void) static int loaded; Color *cp; - dc.collen = MAX(colornamelen, 256); + dc.collen = MAX(LEN(colorname), 256); dc.col = xmalloc(dc.collen * sizeof(Color)); if (loaded) { @@ -1653,16 +1645,16 @@ kmap(KeySym k, uint state) int i; /* Check for mapped keys out of X11 function keys. */ - for (i = 0; i < mappedkeyslen; i++) { + for (i = 0; i < LEN(mappedkeys); i++) { if (mappedkeys[i] == k) break; } - if (i == mappedkeyslen) { + if (i == LEN(mappedkeys)) { if ((k & 0xFFFF) < 0xFD00) return NULL; } - for (kp = key; kp < key + keyslen; kp++) { + for (kp = key; kp < key + LEN(key); kp++) { if (kp->k != k) continue; @@ -1702,7 +1694,7 @@ kpress(XEvent *ev) len = XmbLookupString(xw.xic, e, buf, sizeof buf, &ksym, &status); /* 1. shortcuts */ - for (bp = shortcuts; bp < shortcuts + shortcutslen; bp++) { + for (bp = shortcuts; bp < shortcuts + LEN(shortcuts); bp++) { if (ksym == bp->keysym && match(bp->mod, e->state)) { bp->func(&(bp->arg)); return; From 3e44ee5569a81ba6f06e1ecd19bf0ceb1e97f18d Mon Sep 17 00:00:00 2001 From: "Devin J. Pohly" Date: Tue, 10 Oct 2017 10:30:23 -0500 Subject: [PATCH 029/129] Call xsetenv() in main process instead of child This makes xsetenv internal to x.c, and allows iso14755's external command to use $WINDOWID instead of having to snprintf it again. (The same benefit will apply to the externalpipe patch.) The xwinid function is no longer needed. Signed-off-by: Devin J. Pohly --- st.c | 8 ++------ win.h | 2 -- x.c | 8 ++------ 3 files changed, 4 insertions(+), 14 deletions(-) diff --git a/st.c b/st.c index 7c7ddff..668b312 100644 --- a/st.c +++ b/st.c @@ -60,7 +60,7 @@ char *argv0; #define ISDELIM(u) (utf8strchr(worddelimiters, u) != NULL) /* constants */ -#define ISO14755CMD "dmenu -w %lu -p codepoint: pw_dir, 1); setenv("TERM", termname, 1); - xsetenv(); signal(SIGCHLD, SIG_DFL); signal(SIGHUP, SIG_DFL); @@ -1993,14 +1992,11 @@ tprinter(char *s, size_t len) void iso14755(const Arg *arg) { - unsigned long id = xwinid(); - char cmd[sizeof(ISO14755CMD) + NUMMAXLEN(id)]; FILE *p; char *us, *e, codepoint[9], uc[UTF_SIZ]; unsigned long utf32; - snprintf(cmd, sizeof(cmd), ISO14755CMD, id); - if (!(p = popen(cmd, "r"))) + if (!(p = popen(ISO14755CMD, "r"))) return; us = fgets(codepoint, sizeof(codepoint), p); diff --git a/win.h b/win.h index 428111c..423c114 100644 --- a/win.h +++ b/win.h @@ -19,12 +19,10 @@ void xinit(void); void xloadcols(void); int xsetcolorname(int, const char *); void xloadfonts(char *, double); -void xsetenv(void); void xsettitle(char *); void xsetpointermotion(int); void xseturgency(int); void xunloadfonts(void); void xresize(int, int); void xselpaste(void); -unsigned long xwinid(void); void xsetsel(char *, Time); diff --git a/x.c b/x.c index c484dfc..df2a88c 100644 --- a/x.c +++ b/x.c @@ -89,6 +89,7 @@ static void xdrawcursor(void); static int xgeommasktogravity(int); static int xloadfont(Font *, FcPattern *); static void xunloadfont(Font *); +static void xsetenv(void); static void expose(XEvent *); static void visibility(XEvent *); @@ -1487,12 +1488,6 @@ xbell(int vol) XkbBell(xw.dpy, xw.win, vol, (Atom)NULL); } -unsigned long -xwinid(void) -{ - return xw.win; -} - void focus(XEvent *ev) { @@ -1765,6 +1760,7 @@ main(int argc, char *argv[]) XSetLocaleModifiers(""); tnew(MAX(cols, 1), MAX(rows, 1)); xinit(); + xsetenv(); selinit(); run(); From 416dd257274fd334be082b1138338adffa3e2d5e Mon Sep 17 00:00:00 2001 From: "Devin J. Pohly" Date: Tue, 17 Oct 2017 16:46:26 -0500 Subject: [PATCH 030/129] Move X-related config.h types into x.c No need to expose Shortcut, MouseShortcut, and Key anymore. Signed-off-by: Devin J. Pohly --- st.h | 23 ----------------------- x.c | 24 ++++++++++++++++++++++++ 2 files changed, 24 insertions(+), 23 deletions(-) diff --git a/st.h b/st.h index 9314607..71c79f4 100644 --- a/st.h +++ b/st.h @@ -134,12 +134,6 @@ typedef struct { int cursor; /* cursor style */ } TermWindow; -typedef struct { - uint b; - uint mask; - char *s; -} MouseShortcut; - typedef struct { int mode; int type; @@ -170,23 +164,6 @@ typedef union { const void *v; } Arg; -typedef struct { - uint mod; - KeySym keysym; - void (*func)(const Arg *); - const Arg arg; -} Shortcut; - -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; - void die(const char *, ...); void redraw(void); diff --git a/x.c b/x.c index 03555d1..24f6991 100644 --- a/x.c +++ b/x.c @@ -20,6 +20,30 @@ static char *argv0; #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 */ + signed char crlf; /* crlf mode */ +} Key; + /* function definitions used in config.h */ static void clipcopy(const Arg *); static void clippaste(const Arg *); From 3518dba2a5fb57f601b74528ddeb67f173e4024b Mon Sep 17 00:00:00 2001 From: "Devin J. Pohly" Date: Tue, 10 Oct 2017 11:11:27 -0500 Subject: [PATCH 031/129] Move usage() to be with run() in x.c run/usage/xinit are now all internal to x.c Signed-off-by: Devin J. Pohly --- st.c | 15 --------------- st.h | 2 -- win.h | 2 -- x.c | 18 ++++++++++++++++++ 4 files changed, 18 insertions(+), 19 deletions(-) diff --git a/st.c b/st.c index 668b312..6338510 100644 --- a/st.c +++ b/st.c @@ -28,8 +28,6 @@ #include #include -char *argv0; - #define Glyph Glyph_ #define Font Font_ @@ -2687,16 +2685,3 @@ cresize(int width, int height) tresize(col, row); xresize(col, row); } - -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); -} diff --git a/st.h b/st.h index 44d4938..28a751d 100644 --- a/st.h +++ b/st.h @@ -214,8 +214,6 @@ size_t utf8encode(Rune, char *); void *xmalloc(size_t); char *xstrdup(char *); -void usage(void); - /* Globals */ extern TermWindow win; extern Term term; diff --git a/win.h b/win.h index 423c114..60cecb1 100644 --- a/win.h +++ b/win.h @@ -9,13 +9,11 @@ typedef XftGlyphFontSpec GlyphFontSpec; void draw(void); void drawregion(int, int, int, int); -void run(void); void xbell(int); void xclipcopy(void); void xclippaste(void); void xhints(void); -void xinit(void); void xloadcols(void); int xsetcolorname(int, const char *); void xloadfonts(char *, double); diff --git a/x.c b/x.c index df2a88c..f660ca3 100644 --- a/x.c +++ b/x.c @@ -15,6 +15,7 @@ #include #include +static char *argv0; #include "arg.h" #define Glyph Glyph_ @@ -87,6 +88,7 @@ static void xdrawglyph(Glyph, int, int); static void xclear(int, int, int, int); static void xdrawcursor(void); static int xgeommasktogravity(int); +static void xinit(void); static int xloadfont(Font *, FcPattern *); static void xunloadfont(Font *); static void xsetenv(void); @@ -110,6 +112,9 @@ static void selcopy(Time); static void getbuttoninfo(XEvent *); static void mousereport(XEvent *); +static void run(void); +static void usage(void); + static void (*handler[LASTEvent])(XEvent *) = { [KeyPress] = kpress, [ClientMessage] = cmessage, @@ -1698,6 +1703,19 @@ run(void) } } +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[]) { From 323d38da20c8a1d295ab1dbc0fc7ce947ef824e1 Mon Sep 17 00:00:00 2001 From: "Devin J. Pohly" Date: Mon, 6 Nov 2017 17:57:45 -0600 Subject: [PATCH 032/129] Make win variable internal to x.c There was only a single reference to the `win` variable in st.c, so exporting that to x.c allows us to rid ourselves of another extern. Signed-off-by: Devin J. Pohly --- st.c | 6 +----- st.h | 1 - win.h | 1 + x.c | 11 +++++++++++ 4 files changed, 13 insertions(+), 6 deletions(-) diff --git a/st.c b/st.c index ec747cc..fdf697b 100644 --- a/st.c +++ b/st.c @@ -170,7 +170,6 @@ static char *base64dec(const char *); static ssize_t xwrite(int, const char *, size_t); /* Globals */ -TermWindow win; Term term; Selection sel; int cmdfd; @@ -1683,11 +1682,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; - } - win.cursor = csiescseq.arg[0]; break; default: goto unknown; diff --git a/st.h b/st.h index 71c79f4..8637d35 100644 --- a/st.h +++ b/st.h @@ -201,7 +201,6 @@ void *xrealloc(void *, size_t); char *xstrdup(char *); /* Globals */ -extern TermWindow win; extern Term term; extern Selection sel; extern int cmdfd; diff --git a/win.h b/win.h index beb458d..c6a5337 100644 --- a/win.h +++ b/win.h @@ -14,5 +14,6 @@ void xhints(void); void xloadcols(void); int xsetcolorname(int, const char *); void xsettitle(char *); +int xsetcursor(int); void xsetpointermotion(int); void xsetsel(char *, Time); diff --git a/x.c b/x.c index 24f6991..04e2e05 100644 --- a/x.c +++ b/x.c @@ -187,6 +187,7 @@ static void (*handler[LASTEvent])(XEvent *) = { static DC dc; static XWindow xw; static XSelection xsel; +static TermWindow win; enum window_state { WIN_VISIBLE = 1, @@ -1615,6 +1616,16 @@ xsetpointermotion(int set) XChangeWindowAttributes(xw.dpy, xw.win, CWEventMask, &xw.attrs); } +int +xsetcursor(int cursor) +{ + DEFAULT(cursor, 1); + if (!BETWEEN(cursor, 0, 6)) + return 1; + win.cursor = cursor; + return 0; +} + void xseturgency(int add) { From d5275012b45149a2a6e94679609aacca478221ad Mon Sep 17 00:00:00 2001 From: "Devin J. Pohly" Date: Tue, 10 Oct 2017 11:30:36 -0500 Subject: [PATCH 033/129] Move zoom functions into x.c This makes x(un)loadfonts internal to x.c. Needed to reorder includes and move a typedef to keep the compiler happy. Signed-off-by: Devin J. Pohly --- st.c | 36 +----------------------------------- st.h | 1 + win.h | 7 +++---- x.c | 35 ++++++++++++++++++++++++++++++++++- 4 files changed, 39 insertions(+), 40 deletions(-) diff --git a/st.c b/st.c index 6338510..f1f7bc1 100644 --- a/st.c +++ b/st.c @@ -31,8 +31,8 @@ #define Glyph Glyph_ #define Font Font_ -#include "win.h" #include "st.h" +#include "win.h" #if defined(__linux) #include @@ -128,9 +128,6 @@ 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 printsel(const Arg *); static void printscreen(const Arg *) ; static void iso14755(const Arg *); @@ -2573,37 +2570,6 @@ tresize(int col, int row) term.c = c; } -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); - ttyresize(); - redraw(); - xhints(); -} - -void -zoomreset(const Arg *arg) -{ - Arg larg; - - if (defaultfontsize > 0) { - larg.f = defaultfontsize; - zoomabs(&larg); - } -} - void resettitle(void) { diff --git a/st.h b/st.h index 28a751d..9ece72f 100644 --- a/st.h +++ b/st.h @@ -100,6 +100,7 @@ typedef struct { } Glyph; typedef Glyph *Line; +typedef XftGlyphFontSpec GlyphFontSpec; typedef struct { Glyph attr; /* current char attributes */ diff --git a/win.h b/win.h index 60cecb1..ea45e60 100644 --- a/win.h +++ b/win.h @@ -5,8 +5,6 @@ #define XK_NO_MOD 0 #define XK_SWITCH_MOD (1<<13) -typedef XftGlyphFontSpec GlyphFontSpec; - void draw(void); void drawregion(int, int, int, int); @@ -16,11 +14,12 @@ void xclippaste(void); void xhints(void); void xloadcols(void); int xsetcolorname(int, const char *); -void xloadfonts(char *, double); void xsettitle(char *); void xsetpointermotion(int); void xseturgency(int); -void xunloadfonts(void); void xresize(int, int); void xselpaste(void); void xsetsel(char *, Time); +void zoom(const Arg *); +void zoomabs(const Arg *); +void zoomreset(const Arg *); diff --git a/x.c b/x.c index f660ca3..426ca28 100644 --- a/x.c +++ b/x.c @@ -21,8 +21,8 @@ static char *argv0; #define Glyph Glyph_ #define Font Font_ -#include "win.h" #include "st.h" +#include "win.h" /* XEMBED messages */ #define XEMBED_FOCUS_IN 4 @@ -90,7 +90,9 @@ static void xdrawcursor(void); static int xgeommasktogravity(int); static void xinit(void); static int xloadfont(Font *, FcPattern *); +static void xloadfonts(char *, double); static void xunloadfont(Font *); +static void xunloadfonts(void); static void xsetenv(void); static void expose(XEvent *); @@ -164,6 +166,37 @@ typedef struct { static Fontcache frc[16]; static int frclen = 0; +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); + ttyresize(); + redraw(); + xhints(); +} + +void +zoomreset(const Arg *arg) +{ + Arg larg; + + if (defaultfontsize > 0) { + larg.f = defaultfontsize; + zoomabs(&larg); + } +} + void getbuttoninfo(XEvent *e) { From 3bb900cd6c1c7a5364bd79bce63fdd8711bc878b Mon Sep 17 00:00:00 2001 From: "Devin J. Pohly" Date: Mon, 6 Nov 2017 18:25:58 -0600 Subject: [PATCH 034/129] Remove Time argument from xsetsel This is an X type and should be internal to x.c. The selcopy() function was a single line and only used in one place, so it was inlined to reduce LOC. Signed-off-by: Devin J. Pohly --- st.c | 2 +- win.h | 2 +- x.c | 18 +++++++++--------- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/st.c b/st.c index fdf697b..bcb6473 100644 --- a/st.c +++ b/st.c @@ -1747,7 +1747,7 @@ strhandle(void) dec = base64dec(strescseq.args[2]); if (dec) { - xsetsel(dec, CurrentTime); + xsetsel(dec); xclipcopy(); } else { fprintf(stderr, "erresc: invalid base64\n"); diff --git a/win.h b/win.h index c6a5337..f95a679 100644 --- a/win.h +++ b/win.h @@ -16,4 +16,4 @@ int xsetcolorname(int, const char *); void xsettitle(char *); int xsetcursor(int); void xsetpointermotion(int); -void xsetsel(char *, Time); +void xsetsel(char *); diff --git a/x.c b/x.c index 04e2e05..a332ac9 100644 --- a/x.c +++ b/x.c @@ -148,7 +148,7 @@ static void propnotify(XEvent *); static void selnotify(XEvent *); static void selclear_(XEvent *); static void selrequest(XEvent *); -static void selcopy(Time); +static void setsel(char *, Time); static void getbuttoninfo(XEvent *); static void mousereport(XEvent *); static char *kmap(KeySym, uint); @@ -440,12 +440,6 @@ bpress(XEvent *e) } } -void -selcopy(Time t) -{ - xsetsel(getsel(), t); -} - void propnotify(XEvent *e) { @@ -620,7 +614,7 @@ selrequest(XEvent *e) } void -xsetsel(char *str, Time t) +setsel(char *str, Time t) { free(sel.primary); sel.primary = str; @@ -630,6 +624,12 @@ xsetsel(char *str, Time t) selclear_(NULL); } +void +xsetsel(char *str) +{ + setsel(str, CurrentTime); +} + void brelease(XEvent *e) { @@ -643,7 +643,7 @@ brelease(XEvent *e) } else if (e->xbutton.button == Button1) { if (sel.mode == SEL_READY) { getbuttoninfo(e); - selcopy(e->xbutton.time); + setsel(getsel(), e->xbutton.time); } else selclear_(NULL); sel.mode = SEL_IDLE; From 626b0ae40c71b6c1e02ece79bf033432647381a6 Mon Sep 17 00:00:00 2001 From: "Devin J. Pohly" Date: Tue, 10 Oct 2017 12:01:18 -0500 Subject: [PATCH 035/129] Move window urgency handling entirely into x.c This allows us to make xseturgency internal. Signed-off-by: Devin J. Pohly --- config.def.h | 2 +- st.c | 5 +---- st.h | 1 + win.h | 3 +-- x.c | 8 ++++++-- 5 files changed, 10 insertions(+), 9 deletions(-) diff --git a/config.def.h b/config.def.h index 877afab..dd94be2 100644 --- a/config.def.h +++ b/config.def.h @@ -60,7 +60,7 @@ unsigned int cursorthickness = 2; * bell volume. It must be a value between -100 and 100. Use 0 for disabling * it */ -static int bellvolume = 0; +int bellvolume = 0; /* default TERM value */ char termname[] = "st-256color"; diff --git a/st.c b/st.c index f1f7bc1..df43fac 100644 --- a/st.c +++ b/st.c @@ -2176,10 +2176,7 @@ tcontrolcode(uchar ascii) /* backwards compatibility to xterm */ strhandle(); } else { - if (!(win.state & WIN_FOCUSED)) - xseturgency(1); - if (bellvolume) - xbell(bellvolume); + xbell(); } break; case '\033': /* ESC */ diff --git a/st.h b/st.h index 9ece72f..ad94351 100644 --- a/st.h +++ b/st.h @@ -246,6 +246,7 @@ extern int allowaltscreen; extern unsigned int xfps; extern unsigned int actionfps; extern unsigned int cursorthickness; +extern int bellvolume; extern unsigned int blinktimeout; extern char termname[]; extern const char *colorname[]; diff --git a/win.h b/win.h index ea45e60..dee0b7f 100644 --- a/win.h +++ b/win.h @@ -8,7 +8,7 @@ void draw(void); void drawregion(int, int, int, int); -void xbell(int); +void xbell(void); void xclipcopy(void); void xclippaste(void); void xhints(void); @@ -16,7 +16,6 @@ void xloadcols(void); int xsetcolorname(int, const char *); void xsettitle(char *); void xsetpointermotion(int); -void xseturgency(int); void xresize(int, int); void xselpaste(void); void xsetsel(char *, Time); diff --git a/x.c b/x.c index 426ca28..5b3c97b 100644 --- a/x.c +++ b/x.c @@ -94,6 +94,7 @@ static void xloadfonts(char *, double); static void xunloadfont(Font *); static void xunloadfonts(void); static void xsetenv(void); +static void xseturgency(int); static void expose(XEvent *); static void visibility(XEvent *); @@ -1521,9 +1522,12 @@ xseturgency(int add) } void -xbell(int vol) +xbell(void) { - XkbBell(xw.dpy, xw.win, vol, (Atom)NULL); + if (!(win.state & WIN_FOCUSED)) + xseturgency(1); + if (bellvolume) + XkbBell(xw.dpy, xw.win, bellvolume, (Atom)NULL); } void From 8b564c1a3f51c08e64c2f589852a02b8595d44ca Mon Sep 17 00:00:00 2001 From: "Devin J. Pohly" Date: Mon, 6 Nov 2017 18:30:45 -0600 Subject: [PATCH 036/129] Remove X and fontconfig from st.c None of the X-related includes are needed any longer. In addition, move the X modifier defines into x.c, as they are not used outside. Signed-off-by: Devin J. Pohly --- st.c | 5 ----- win.h | 5 ----- x.c | 5 +++++ 3 files changed, 5 insertions(+), 10 deletions(-) diff --git a/st.c b/st.c index bcb6473..9cfa547 100644 --- a/st.c +++ b/st.c @@ -21,13 +21,8 @@ #include #include #include -#include #include -/* X11 */ -#include -#include - #include "st.h" #include "win.h" diff --git a/win.h b/win.h index f95a679..123662e 100644 --- a/win.h +++ b/win.h @@ -1,10 +1,5 @@ /* See LICENSE for license details. */ -/* X modifiers */ -#define XK_ANY_MOD UINT_MAX -#define XK_NO_MOD 0 -#define XK_SWITCH_MOD (1<<13) - void draw(void); void drawregion(int, int, int, int); diff --git a/x.c b/x.c index a332ac9..e5b236d 100644 --- a/x.c +++ b/x.c @@ -44,6 +44,11 @@ typedef struct { signed char crlf; /* crlf mode */ } 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 *); From a09138afa57adb4b76dba8ca72dc7ee2642a5c8d Mon Sep 17 00:00:00 2001 From: "Devin J. Pohly" Date: Tue, 10 Oct 2017 12:17:25 -0500 Subject: [PATCH 037/129] Move font/fontspec variables into x.c and XWindow Signed-off-by: Devin J. Pohly --- st.c | 11 ----------- st.h | 8 ++------ x.c | 18 +++++++++++++----- 3 files changed, 15 insertions(+), 22 deletions(-) diff --git a/st.c b/st.c index df43fac..540b487 100644 --- a/st.c +++ b/st.c @@ -28,9 +28,6 @@ #include #include -#define Glyph Glyph_ -#define Font Font_ - #include "st.h" #include "win.h" @@ -196,7 +193,6 @@ static size_t utf8validate(Rune *, size_t); static char *base64dec(const char *); static ssize_t xwrite(int, const char *, size_t); -static void *xrealloc(void *, size_t); /* Globals */ TermWindow win; @@ -218,10 +214,6 @@ static CSIEscape csiescseq; static STREscape strescseq; static int iofd = 1; -char *usedfont = NULL; -double usedfontsize = 0; -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}; @@ -2516,9 +2508,6 @@ tresize(int col, int row) free(term.alt[i]); } - /* resize to new width */ - term.specbuf = xrealloc(term.specbuf, col * sizeof(GlyphFontSpec)); - /* resize to new height */ term.line = xrealloc(term.line, row * sizeof(Line)); term.alt = xrealloc(term.alt, row * sizeof(Line)); diff --git a/st.h b/st.h index ad94351..2199c13 100644 --- a/st.h +++ b/st.h @@ -92,6 +92,7 @@ typedef unsigned short ushort; typedef uint_least32_t Rune; +#define Glyph Glyph_ typedef struct { Rune u; /* character code */ ushort mode; /* attribute flags */ @@ -100,7 +101,6 @@ typedef struct { } Glyph; typedef Glyph *Line; -typedef XftGlyphFontSpec GlyphFontSpec; typedef struct { Glyph attr; /* current char attributes */ @@ -116,7 +116,6 @@ typedef struct { Line *line; /* screen */ Line *alt; /* alternate screen */ int *dirty; /* dirtyness of lines */ - GlyphFontSpec *specbuf; /* font spec buffer used for rendering */ TCursor c; /* cursor */ int top; /* top scroll limit */ int bot; /* bottom scroll limit */ @@ -213,6 +212,7 @@ size_t utf8decode(char *, Rune *, size_t); size_t utf8encode(Rune, char *); void *xmalloc(size_t); +void *xrealloc(void *, size_t); char *xstrdup(char *); /* Globals */ @@ -231,10 +231,6 @@ extern char *opt_name; extern char *opt_title; extern int oldbutton; -extern char *usedfont; -extern double usedfontsize; -extern double defaultfontsize; - /* config.h globals */ extern char font[]; extern int borderpx; diff --git a/x.c b/x.c index 5b3c97b..186e408 100644 --- a/x.c +++ b/x.c @@ -17,10 +17,6 @@ static char *argv0; #include "arg.h" - -#define Glyph Glyph_ -#define Font Font_ - #include "st.h" #include "win.h" @@ -35,6 +31,7 @@ static char *argv0; typedef XftDraw *Draw; typedef XftColor Color; +typedef XftGlyphFontSpec GlyphFontSpec; /* Purely graphic info */ typedef struct { @@ -42,6 +39,7 @@ typedef struct { Colormap cmap; Window win; Drawable buf; + GlyphFontSpec *specbuf; /* font spec buffer used for rendering */ Atom xembed, wmdeletewin, netwmname, netwmpid; XIM xim; XIC xic; @@ -59,6 +57,7 @@ typedef struct { } XSelection; /* Font structure */ +#define Font Font_ typedef struct { int height; int width; @@ -166,6 +165,9 @@ typedef struct { /* 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; void zoom(const Arg *arg) @@ -605,6 +607,9 @@ xresize(int col, int row) DefaultDepth(xw.dpy, xw.scr)); 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 @@ -965,6 +970,9 @@ xinit(void) 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(term.col * sizeof(GlyphFontSpec)); + /* Xft rendering context */ xw.draw = XftDrawCreate(xw.dpy, xw.buf, xw.vis, xw.cmap); @@ -1456,7 +1464,7 @@ drawregion(int x1, int y1, int x2, int y2) term.dirty[y] = 0; - specs = term.specbuf; + specs = xw.specbuf; numspecs = xmakeglyphfontspecs(specs, &term.line[y][x1], x2 - x1, x1, y); i = ox = 0; From d84f3f4bd15e7d65fc0334cf7d62913c901bad00 Mon Sep 17 00:00:00 2001 From: "Devin J. Pohly" Date: Wed, 21 Feb 2018 22:28:41 -0600 Subject: [PATCH 038/129] Rely on ttyresize to set tty size This removes ttynew's dependency on cresize being called first, and then allows us to absorb the ttyresize call into cresize (which always precedes it). Signed-off-by: Devin J. Pohly --- st.c | 3 +-- x.c | 6 ++---- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/st.c b/st.c index 9cfa547..dae7b91 100644 --- a/st.c +++ b/st.c @@ -670,7 +670,6 @@ void ttynew(char *line, char *out, char **args) { int m, s; - struct winsize w = {term.row, term.col, 0, 0}; if (out) { term.mode |= MODE_PRINT; @@ -691,7 +690,7 @@ ttynew(char *line, char *out, char **args) } /* 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()) { diff --git a/x.c b/x.c index e5b236d..7bfa1b7 100644 --- a/x.c +++ b/x.c @@ -276,7 +276,6 @@ zoomabs(const Arg *arg) xunloadfonts(); xloadfonts(usedfont, arg->f); cresize(0, 0); - ttyresize(win.tw, win.th); redraw(); xhints(); } @@ -695,6 +694,7 @@ cresize(int width, int height) tresize(col, row); xresize(col, row); + ttyresize(win.tw, win.th); } void @@ -1794,7 +1794,6 @@ resize(XEvent *e) return; cresize(e->xconfigure.width, e->xconfigure.height); - ttyresize(win.tw, win.th); } void @@ -1823,9 +1822,8 @@ run(void) } } while (ev.type != MapNotify); - cresize(w, h); ttynew(opt_line, opt_io, opt_cmd); - ttyresize(win.tw, win.th); + cresize(w, h); clock_gettime(CLOCK_MONOTONIC, &last); lastblink = last; From a8314643b1aeaa2187dad71dc5748aaac1760c1b Mon Sep 17 00:00:00 2001 From: "Devin J. Pohly" Date: Tue, 10 Oct 2017 12:46:53 -0500 Subject: [PATCH 039/129] Move window-manipulating functions into x.c xresize is now internal to x.c Signed-off-by: Devin J. Pohly --- st.c | 36 ------------------------------------ st.h | 9 +-------- win.h | 1 - x.c | 45 ++++++++++++++++++++++++++++++++++++++++++++- 4 files changed, 45 insertions(+), 46 deletions(-) diff --git a/st.c b/st.c index 540b487..75c191d 100644 --- a/st.c +++ b/st.c @@ -165,7 +165,6 @@ 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 tsetattr(int *, int); @@ -419,24 +418,6 @@ selinit(void) sel.clipboard = NULL; } -int -x2col(int x) -{ - x -= borderpx; - x /= win.cw; - - return LIMIT(x, 0, term.col-1); -} - -int -y2row(int y) -{ - y -= borderpx; - y /= win.ch; - - return LIMIT(y, 0, term.row-1); -} - int tlinelen(int y) { @@ -2620,20 +2601,3 @@ kmap(KeySym k, uint state) return NULL; } - -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); -} diff --git a/st.h b/st.h index 2199c13..5d44411 100644 --- a/st.h +++ b/st.h @@ -80,11 +80,6 @@ enum selection_snap { SNAP_LINE = 2 }; -enum window_state { - WIN_VISIBLE = 1, - WIN_FOCUSED = 2 -}; - typedef unsigned char uchar; typedef unsigned int uint; typedef unsigned long ulong; @@ -186,6 +181,7 @@ void redraw(void); int tattrset(int); void tnew(int, int); +void tresize(int, int); void tsetdirt(int, int); void tsetdirtattr(int); int match(uint, uint); @@ -198,15 +194,12 @@ void ttywrite(const char *, size_t); void resettitle(void); char *kmap(KeySym, uint); -void cresize(int, int); void selclear(void); void selinit(void); void selnormalize(void); int selected(int, int); char *getsel(void); -int x2col(int); -int y2row(int); size_t utf8decode(char *, Rune *, size_t); size_t utf8encode(Rune, char *); diff --git a/win.h b/win.h index dee0b7f..00113c5 100644 --- a/win.h +++ b/win.h @@ -16,7 +16,6 @@ void xloadcols(void); int xsetcolorname(int, const char *); void xsettitle(char *); void xsetpointermotion(int); -void xresize(int, int); void xselpaste(void); void xsetsel(char *, Time); void zoom(const Arg *); diff --git a/x.c b/x.c index 186e408..01ef1b0 100644 --- a/x.c +++ b/x.c @@ -88,12 +88,16 @@ static void xclear(int, int, int, int); static void xdrawcursor(void); static int xgeommasktogravity(int); static void xinit(void); +static void cresize(int, int); +static void xresize(int, int); 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 x2col(int); +static int y2row(int); static void expose(XEvent *); static void visibility(XEvent *); @@ -109,7 +113,6 @@ static void propnotify(XEvent *); static void selnotify(XEvent *); static void selclear_(XEvent *); static void selrequest(XEvent *); - static void selcopy(Time); static void getbuttoninfo(XEvent *); static void mousereport(XEvent *); @@ -148,6 +151,11 @@ static DC dc; static XWindow xw; static XSelection xsel; +enum window_state { + WIN_VISIBLE = 1, + WIN_FOCUSED = 2 +}; + /* Font Ring Cache */ enum { FRC_NORMAL, @@ -200,6 +208,24 @@ zoomreset(const Arg *arg) } } +int +x2col(int x) +{ + x -= borderpx; + x /= win.cw; + + return LIMIT(x, 0, term.col-1); +} + +int +y2row(int y) +{ + y -= borderpx; + y /= win.ch; + + return LIMIT(y, 0, term.row-1); +} + void getbuttoninfo(XEvent *e) { @@ -596,6 +622,23 @@ bmotion(XEvent *e) tsetdirt(MIN(sel.nb.y, oldsby), MAX(sel.ne.y, oldsey)); } +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); +} + void xresize(int col, int row) { From 138caf294ea4d7968df36ead9d5ff5fc49f6215f Mon Sep 17 00:00:00 2001 From: "Devin J. Pohly" Date: Wed, 21 Feb 2018 22:48:28 -0600 Subject: [PATCH 040/129] Have selected() check whether selection exists Signed-off-by: Devin J. Pohly --- st.c | 3 ++- x.c | 10 ++++------ 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/st.c b/st.c index dae7b91..d4dfe6e 100644 --- a/st.c +++ b/st.c @@ -419,7 +419,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) diff --git a/x.c b/x.c index 7bfa1b7..e3e5451 100644 --- a/x.c +++ b/x.c @@ -1418,7 +1418,6 @@ 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); @@ -1434,7 +1433,7 @@ xdrawcursor(void) /* remove the old cursor */ og = term.line[oldy][oldx]; - if (ena_sel && selected(oldx, oldy)) + if (selected(oldx, oldy)) og.mode ^= ATTR_REVERSE; xdrawglyph(og, oldx, oldy); @@ -1448,7 +1447,7 @@ xdrawcursor(void) if (IS_SET(MODE_REVERSE)) { g.mode |= ATTR_REVERSE; g.bg = defaultfg; - if (ena_sel && selected(term.c.x, term.c.y)) { + if (selected(term.c.x, term.c.y)) { drawcol = dc.col[defaultcs]; g.fg = defaultrcs; } else { @@ -1456,7 +1455,7 @@ xdrawcursor(void) g.fg = defaultcs; } } else { - if (ena_sel && selected(term.c.x, term.c.y)) { + if (selected(term.c.x, term.c.y)) { drawcol = dc.col[defaultrcs]; g.fg = defaultfg; g.bg = defaultrcs; @@ -1555,7 +1554,6 @@ 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 (!(win.state & WIN_VISIBLE)) return; @@ -1574,7 +1572,7 @@ drawregion(int x1, int y1, int x2, int y2) new = term.line[y][x]; if (new.mode == ATTR_WDUMMY) continue; - if (ena_sel && selected(x, y)) + if (selected(x, y)) new.mode ^= ATTR_REVERSE; if (i > 0 && ATTRCMP(base, new)) { xdrawglyphfontspecs(specs, base, i, ox, y); From dbe8676d7d69651132bde2b6d9ec3787cbbc552a Mon Sep 17 00:00:00 2001 From: "Devin J. Pohly" Date: Tue, 10 Oct 2017 15:51:23 -0500 Subject: [PATCH 041/129] Pass new dimensions into ttyresize This removes another reference to TermWindow from st.c. Signed-off-by: Devin J. Pohly --- st.c | 6 +++--- st.h | 2 +- x.c | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/st.c b/st.c index 75c191d..839dc94 100644 --- a/st.c +++ b/st.c @@ -905,14 +905,14 @@ ttysend(char *s, size_t n) } void -ttyresize(void) +ttyresize(int tw, int th) { struct winsize w; w.ws_row = term.row; w.ws_col = term.col; - w.ws_xpixel = win.tw; - w.ws_ypixel = win.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)); } diff --git a/st.h b/st.h index 5d44411..372462d 100644 --- a/st.h +++ b/st.h @@ -187,7 +187,7 @@ void tsetdirtattr(int); int match(uint, uint); void ttynew(void); size_t ttyread(void); -void ttyresize(void); +void ttyresize(int, int); void ttysend(char *, size_t); void ttywrite(const char *, size_t); diff --git a/x.c b/x.c index 01ef1b0..1b656ac 100644 --- a/x.c +++ b/x.c @@ -192,7 +192,7 @@ zoomabs(const Arg *arg) xunloadfonts(); xloadfonts(usedfont, arg->f); cresize(0, 0); - ttyresize(); + ttyresize(win.tw, win.th); redraw(); xhints(); } @@ -1679,7 +1679,7 @@ resize(XEvent *e) return; cresize(e->xconfigure.width, e->xconfigure.height); - ttyresize(); + ttyresize(win.tw, win.th); } void @@ -1710,7 +1710,7 @@ run(void) cresize(w, h); ttynew(); - ttyresize(); + ttyresize(win.tw, win.th); clock_gettime(CLOCK_MONOTONIC, &last); lastblink = last; From 5683b1f80c5ac274adf98517ce2217b4d4896243 Mon Sep 17 00:00:00 2001 From: "Devin J. Pohly" Date: Wed, 21 Feb 2018 22:56:02 -0600 Subject: [PATCH 042/129] Move X-specific selection info into XSelection Data about PRIMARY/CLIPBOARD and clicks are part of the front-end, not the terminal. Signed-off-by: Devin J. Pohly --- st.c | 4 ---- st.h | 5 ----- x.c | 31 +++++++++++++++++++------------ 3 files changed, 19 insertions(+), 21 deletions(-) diff --git a/st.c b/st.c index d4dfe6e..ea0726c 100644 --- a/st.c +++ b/st.c @@ -365,13 +365,9 @@ base64dec(const char *src) 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; } int diff --git a/st.h b/st.h index 8637d35..79dd47e 100644 --- a/st.h +++ b/st.h @@ -149,12 +149,7 @@ typedef struct { int x, y; } nb, ne, ob, oe; - char *primary, *clipboard; int alt; - struct timespec tclick1; - struct timespec tclick2; - - //Atom xtarget; } Selection; typedef union { diff --git a/x.c b/x.c index e3e5451..9f506b1 100644 --- a/x.c +++ b/x.c @@ -94,6 +94,9 @@ typedef struct { typedef struct { Atom xtarget; + char *primary, *clipboard; + struct timespec tclick1; + struct timespec tclick2; } XSelection; /* Font structure */ @@ -234,11 +237,11 @@ clipcopy(const Arg *dummy) { Atom clipboard; - if (sel.clipboard != NULL) - free(sel.clipboard); + if (xsel.clipboard != NULL) + free(xsel.clipboard); - if (sel.primary != NULL) { - sel.clipboard = xstrdup(sel.primary); + if (xsel.primary != NULL) { + xsel.clipboard = xstrdup(xsel.primary); clipboard = XInternAtom(xw.dpy, "CLIPBOARD", 0); XSetSelectionOwner(xw.dpy, clipboard, xw.win, CurrentTime); } @@ -427,9 +430,9 @@ bpress(XEvent *e) * If the user clicks below predefined timeouts specific * snapping behaviour is exposed. */ - if (TIMEDIFF(now, sel.tclick2) <= tripleclicktimeout) { + if (TIMEDIFF(now, xsel.tclick2) <= tripleclicktimeout) { sel.snap = SNAP_LINE; - } else if (TIMEDIFF(now, sel.tclick1) <= doubleclicktimeout) { + } else if (TIMEDIFF(now, xsel.tclick1) <= doubleclicktimeout) { sel.snap = SNAP_WORD; } else { sel.snap = 0; @@ -439,8 +442,8 @@ bpress(XEvent *e) if (sel.snap != 0) sel.mode = SEL_READY; tsetdirt(sel.nb.y, sel.ne.y); - sel.tclick2 = sel.tclick1; - sel.tclick1 = now; + xsel.tclick2 = xsel.tclick1; + xsel.tclick1 = now; } } @@ -594,9 +597,9 @@ selrequest(XEvent *e) */ clipboard = XInternAtom(xw.dpy, "CLIPBOARD", 0); if (xsre->selection == XA_PRIMARY) { - seltext = sel.primary; + seltext = xsel.primary; } else if (xsre->selection == clipboard) { - seltext = sel.clipboard; + seltext = xsel.clipboard; } else { fprintf(stderr, "Unhandled clipboard selection 0x%lx\n", @@ -620,8 +623,8 @@ selrequest(XEvent *e) void setsel(char *str, Time t) { - free(sel.primary); - sel.primary = str; + free(xsel.primary); + xsel.primary = str; XSetSelectionOwner(xw.dpy, XA_PRIMARY, xw.win, t); if (XGetSelectionOwner(xw.dpy, XA_PRIMARY) != xw.win) @@ -1127,6 +1130,10 @@ xinit(void) 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; From ed132e11271d18a5d8aa163096bc6192c694bc47 Mon Sep 17 00:00:00 2001 From: "Devin J. Pohly" Date: Wed, 11 Oct 2017 08:47:14 -0500 Subject: [PATCH 043/129] Move key-matching functions into x.c Modifiers and keysyms are specific to X, and the functions match and kmap are only used in x.c. Needed to global-ize the key arrays and lengths from config.h (for now). Signed-off-by: Devin J. Pohly --- config.def.h | 6 +++--- st.c | 58 ++-------------------------------------------------- st.h | 18 +++++++++++++--- x.c | 48 +++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 68 insertions(+), 62 deletions(-) diff --git a/config.def.h b/config.def.h index dd94be2..18cb31c 100644 --- a/config.def.h +++ b/config.def.h @@ -209,13 +209,13 @@ Shortcut shortcuts[] = { * If you want keys other than the X11 function keys (0xFD00 - 0xFFFF) * to be mapped below, add them to this array. */ -static KeySym mappedkeys[] = { -1 }; +KeySym mappedkeys[] = { -1 }; /* * 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; +uint ignoremod = Mod2Mask|XK_SWITCH_MOD; /* * Override mouse-select while mask is active (when MODE_MOUSE is set). @@ -228,7 +228,7 @@ uint forceselmod = ShiftMask; * This is the huge key array which defines all compatibility to the Linux * world. Please decide about changes wisely. */ -static Key key[] = { +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}, diff --git a/st.c b/st.c index 839dc94..1a8fa1f 100644 --- a/st.c +++ b/st.c @@ -110,16 +110,6 @@ typedef struct { int narg; /* nb of args */ } STREscape; -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; - /* function definitions used in config.h */ static void clipcopy(const Arg *); static void clippaste(const Arg *); @@ -223,6 +213,8 @@ size_t colornamelen = LEN(colorname); size_t mshortcutslen = LEN(mshortcuts); size_t shortcutslen = LEN(shortcuts); size_t selmaskslen = LEN(selmasks); +size_t keyslen = LEN(key); +size_t mappedkeyslen = LEN(mappedkeys); ssize_t xwrite(int fd, const char *s, size_t len) @@ -2550,54 +2542,8 @@ redraw(void) draw(); } -int -match(uint mask, uint state) -{ - return mask == XK_ANY_MOD || mask == (state & ~ignoremod); -} - void numlock(const Arg *dummy) { term.numlock ^= 1; } - -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 (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; -} diff --git a/st.h b/st.h index 372462d..c255b7c 100644 --- a/st.h +++ b/st.h @@ -176,6 +176,16 @@ typedef struct { const Arg arg; } Shortcut; +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; + void die(const char *, ...); void redraw(void); @@ -184,7 +194,6 @@ void tnew(int, int); void tresize(int, int); void tsetdirt(int, int); void tsetdirtattr(int); -int match(uint, uint); void ttynew(void); size_t ttyread(void); void ttyresize(int, int); @@ -193,9 +202,7 @@ void ttywrite(const char *, size_t); void resettitle(void); -char *kmap(KeySym, uint); void selclear(void); - void selinit(void); void selnormalize(void); int selected(int, int); @@ -255,7 +262,12 @@ extern MouseShortcut mshortcuts[]; extern size_t mshortcutslen; extern Shortcut shortcuts[]; extern size_t shortcutslen; +extern KeySym mappedkeys[]; +extern size_t mappedkeyslen; +extern uint ignoremod; extern uint forceselmod; +extern Key key[]; +extern size_t keyslen; extern uint selmasks[]; extern size_t selmaskslen; extern char ascii_printable[]; diff --git a/x.c b/x.c index 1b656ac..371a467 100644 --- a/x.c +++ b/x.c @@ -116,6 +116,8 @@ static void selrequest(XEvent *); static void selcopy(Time); static void getbuttoninfo(XEvent *); static void mousereport(XEvent *); +static char *kmap(KeySym, uint); +static int match(uint, uint); static void run(void); static void usage(void); @@ -1603,6 +1605,52 @@ focus(XEvent *ev) } } +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 < mappedkeyslen; i++) { + if (mappedkeys[i] == k) + break; + } + if (i == mappedkeyslen) { + if ((k & 0xFFFF) < 0xFD00) + return NULL; + } + + for (kp = key; kp < key + keyslen; 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) { From bcb5d3adbe57ead05a829e5144c2ba1dc465865f Mon Sep 17 00:00:00 2001 From: "Devin J. Pohly" Date: Wed, 21 Feb 2018 23:29:41 -0600 Subject: [PATCH 044/129] Move terminal-related selection logic into st.c The front-end determines information about mouse clicks and motion, and the terminal handles the actual selection start/extend/dirty logic by row and column. While we're in the neighborhood, we'll also rename getbuttoninfo() to mousesel() which is, at least, less wrong. Signed-off-by: Devin J. Pohly --- st.c | 37 +++++++++++++++++++++++++++++++++++++ st.h | 3 ++- x.c | 55 +++++++++++++++---------------------------------------- 3 files changed, 54 insertions(+), 41 deletions(-) diff --git a/st.c b/st.c index ea0726c..21cba9e 100644 --- a/st.c +++ b/st.c @@ -140,6 +140,7 @@ static void tscrollup(int, int); static void tscrolldown(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 tsetmode(int, int, int *, int); @@ -384,6 +385,42 @@ tlinelen(int y) return i; } +void +selstart(int col, int row, int snap) +{ + 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(); + + if (sel.snap != 0) + sel.mode = SEL_READY; + tsetdirt(sel.nb.y, sel.ne.y); +} + +void +selextend(int col, int row, int type) +{ + int oldey, oldex, oldsby, oldsey, oldtype; + oldey = sel.oe.y; + oldex = sel.oe.x; + oldsby = sel.nb.y; + oldsey = sel.ne.y; + oldtype = sel.type; + + 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)); +} + void selnormalize(void) { diff --git a/st.h b/st.h index 79dd47e..c5ff5cf 100644 --- a/st.h +++ b/st.h @@ -172,7 +172,6 @@ void toggleprinter(const Arg *); int tattrset(int); void tnew(int, int); void tresize(int, int); -void tsetdirt(int, int); void tsetdirtattr(int); void ttynew(char *, char *, char **); size_t ttyread(void); @@ -184,6 +183,8 @@ void resettitle(void); void selclear(void); void selinit(void); +void selstart(int, int, int); +void selextend(int, int, int); void selnormalize(void); int selected(int, int); char *getsel(void); diff --git a/x.c b/x.c index 9f506b1..ddae6b6 100644 --- a/x.c +++ b/x.c @@ -157,7 +157,7 @@ static void selnotify(XEvent *); static void selclear_(XEvent *); static void selrequest(XEvent *); static void setsel(char *, Time); -static void getbuttoninfo(XEvent *); +static void mousesel(XEvent *); static void mousereport(XEvent *); static char *kmap(KeySym, uint); static int match(uint, uint); @@ -313,24 +313,19 @@ y2row(int y) } void -getbuttoninfo(XEvent *e) +mousesel(XEvent *e) { - int type; + int type, seltype = SEL_REGULAR; 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; + seltype = type; break; } } + + selextend(x2col(e->xbutton.x), y2row(e->xbutton.y), seltype); } void @@ -402,6 +397,7 @@ bpress(XEvent *e) { struct timespec now; MouseShortcut *ms; + int snap; if (IS_SET(MODE_MOUSE) && !(e->xbutton.state & forceselmod)) { mousereport(e); @@ -417,33 +413,22 @@ bpress(XEvent *e) } 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. */ + clock_gettime(CLOCK_MONOTONIC, &now); if (TIMEDIFF(now, xsel.tclick2) <= tripleclicktimeout) { - sel.snap = SNAP_LINE; + snap = SNAP_LINE; } else if (TIMEDIFF(now, xsel.tclick1) <= doubleclicktimeout) { - sel.snap = SNAP_WORD; + snap = SNAP_WORD; } else { - sel.snap = 0; + snap = 0; } - selnormalize(); - - if (sel.snap != 0) - sel.mode = SEL_READY; - tsetdirt(sel.nb.y, sel.ne.y); xsel.tclick2 = xsel.tclick1; xsel.tclick1 = now; + + selstart(x2col(e->xbutton.x), y2row(e->xbutton.y), snap); } } @@ -649,20 +634,17 @@ brelease(XEvent *e) selpaste(NULL); } else if (e->xbutton.button == Button1) { if (sel.mode == SEL_READY) { - getbuttoninfo(e); + mousesel(e); setsel(getsel(), 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; @@ -672,14 +654,7 @@ bmotion(XEvent *e) 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)); + mousesel(e); } void From 69e32a61df15787c410a48eaa10a89240c36257d Mon Sep 17 00:00:00 2001 From: "Devin J. Pohly" Date: Thu, 12 Oct 2017 22:25:49 -0500 Subject: [PATCH 045/129] Move opt_* into same file as main()/run() This commit is purely about reducing externs and LOC. If the main and run functions ever move elsewhere (which will probably make sense eventually), these should come along with them. Signed-off-by: Devin J. Pohly --- st.c | 50 ++++++++++++++++++++------------------------------ st.h | 11 ++--------- x.c | 12 +++++++++++- 3 files changed, 33 insertions(+), 40 deletions(-) diff --git a/st.c b/st.c index 1a8fa1f..58f7941 100644 --- a/st.c +++ b/st.c @@ -48,7 +48,6 @@ /* macros */ #define NUMMAXLEN(x) ((int)(sizeof(x) * 2.56 + 0.5) + 1) -#define DEFAULT(a, b) (a) = (a) ? (a) : (b) #define ISCONTROLC0(c) (BETWEEN(c, 0, 0x1f) || (c) == '\177') #define ISCONTROLC1(c) (BETWEEN(c, 0x80, 0x9f)) #define ISCONTROL(c) (ISCONTROLC0(c) || ISCONTROLC1(c)) @@ -124,8 +123,8 @@ static void sendbreak(const Arg *); /* config.h for applying patches and the configuration. */ #include "config.h" -static void execsh(void); -static void stty(void); +static void execsh(char **); +static void stty(char **); static void sigchld(int); static void csidump(void); @@ -189,14 +188,6 @@ Term term; Selection sel; int cmdfd; pid_t pid; -char **opt_cmd = NULL; -char *opt_class = NULL; -char *opt_embed = NULL; -char *opt_font = NULL; -char *opt_io = NULL; -char *opt_line = NULL; -char *opt_name = NULL; -char *opt_title = NULL; int oldbutton = 3; /* button event on startup: 3 = release */ static CSIEscape csiescseq; @@ -634,9 +625,9 @@ die(const char *errstr, ...) } void -execsh(void) +execsh(char **args) { - char **args, *sh, *prog; + char *sh, *prog; const struct passwd *pw; errno = 0; @@ -650,13 +641,13 @@ execsh(void) if ((sh = getenv("SHELL")) == NULL) sh = (pw->pw_shell[0]) ? pw->pw_shell : shell; - 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}; + DEFAULT(args, ((char *[]) {prog, NULL})); unsetenv("COLUMNS"); unsetenv("LINES"); @@ -697,7 +688,7 @@ sigchld(int a) void -stty(void) +stty(char **args) { char cmd[_POSIX_ARG_MAX], **p, *q, *s; size_t n, siz; @@ -707,7 +698,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++ = ' '; @@ -721,26 +712,26 @@ stty(void) } void -ttynew(void) +ttynew(char *line, 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(); + stty(args); return; } @@ -762,7 +753,7 @@ ttynew(void) die("ioctl TIOCSCTTY failed: %s\n", strerror(errno)); close(s); close(m); - execsh(); + execsh(args); break; default: close(s); @@ -1942,8 +1933,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; } @@ -2532,7 +2522,7 @@ tresize(int col, int row) void resettitle(void) { - xsettitle(opt_title ? opt_title : "st"); + xsettitle(NULL); } void diff --git a/st.h b/st.h index c255b7c..09473c2 100644 --- a/st.h +++ b/st.h @@ -9,6 +9,7 @@ #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) @@ -194,7 +195,7 @@ void tnew(int, int); void tresize(int, int); void tsetdirt(int, int); void tsetdirtattr(int); -void ttynew(void); +void ttynew(char *, char *, char **); size_t ttyread(void); void ttyresize(int, int); void ttysend(char *, size_t); @@ -221,14 +222,6 @@ extern Term term; extern Selection sel; extern int cmdfd; extern pid_t pid; -extern char **opt_cmd; -extern char *opt_class; -extern char *opt_embed; -extern char *opt_font; -extern char *opt_io; -extern char *opt_line; -extern char *opt_name; -extern char *opt_title; extern int oldbutton; /* config.h globals */ diff --git a/x.c b/x.c index 371a467..e267961 100644 --- a/x.c +++ b/x.c @@ -179,6 +179,15 @@ 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; + void zoom(const Arg *arg) { @@ -1473,6 +1482,7 @@ void xsettitle(char *p) { XTextProperty prop; + DEFAULT(p, "st"); Xutf8TextListToTextProperty(xw.dpy, &p, 1, XUTF8StringStyle, &prop); @@ -1757,7 +1767,7 @@ run(void) } while (ev.type != MapNotify); cresize(w, h); - ttynew(); + ttynew(opt_line, opt_io, opt_cmd); ttyresize(win.tw, win.th); clock_gettime(CLOCK_MONOTONIC, &last); From cfc7acdfd923924ae150a32061fb95987697b159 Mon Sep 17 00:00:00 2001 From: "Devin J. Pohly" Date: Wed, 21 Feb 2018 23:54:29 -0600 Subject: [PATCH 046/129] Move remaining selection mode logic into selextend The "done" parameter indicates a change which finalizes the selection (e.g. a mouse button release as opposed to motion). Signed-off-by: Devin J. Pohly --- st.c | 14 ++++++++++++-- st.h | 3 +-- x.c | 27 +++++++++------------------ 3 files changed, 22 insertions(+), 22 deletions(-) diff --git a/st.c b/st.c index 21cba9e..b7e215e 100644 --- a/st.c +++ b/st.c @@ -167,11 +167,11 @@ static ssize_t xwrite(int, const char *, size_t); /* Globals */ Term term; -Selection sel; int cmdfd; pid_t pid; int oldbutton = 3; /* button event on startup: 3 = release */ +static Selection sel; static CSIEscape csiescseq; static STREscape strescseq; static int iofd = 1; @@ -402,9 +402,17 @@ selstart(int col, int row, int snap) } void -selextend(int col, int row, int type) +selextend(int col, int row, int type, int done) { int oldey, oldex, oldsby, oldsey, oldtype; + + if (!sel.mode) + return; + if (done && sel.mode == SEL_EMPTY) { + selclear(); + return; + } + oldey = sel.oe.y; oldex = sel.oe.x; oldsby = sel.nb.y; @@ -419,6 +427,8 @@ selextend(int col, int row, int 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 diff --git a/st.h b/st.h index c5ff5cf..a34e31c 100644 --- a/st.h +++ b/st.h @@ -184,7 +184,7 @@ void resettitle(void); void selclear(void); void selinit(void); void selstart(int, int, int); -void selextend(int, int, int); +void selextend(int, int, int, int); void selnormalize(void); int selected(int, int); char *getsel(void); @@ -198,7 +198,6 @@ char *xstrdup(char *); /* Globals */ extern Term term; -extern Selection sel; extern int cmdfd; extern pid_t pid; extern int oldbutton; diff --git a/x.c b/x.c index ddae6b6..a7f619e 100644 --- a/x.c +++ b/x.c @@ -157,7 +157,7 @@ static void selnotify(XEvent *); static void selclear_(XEvent *); static void selrequest(XEvent *); static void setsel(char *, Time); -static void mousesel(XEvent *); +static void mousesel(XEvent *, int); static void mousereport(XEvent *); static char *kmap(KeySym, uint); static int match(uint, uint); @@ -313,7 +313,7 @@ y2row(int y) } void -mousesel(XEvent *e) +mousesel(XEvent *e, int done) { int type, seltype = SEL_REGULAR; uint state = e->xbutton.state & ~(Button1Mask | forceselmod); @@ -324,8 +324,9 @@ mousesel(XEvent *e) break; } } - - selextend(x2col(e->xbutton.x), y2row(e->xbutton.y), seltype); + selextend(x2col(e->xbutton.x), y2row(e->xbutton.y), seltype, done); + if (done) + setsel(getsel(), e->xbutton.time); } void @@ -630,16 +631,10 @@ brelease(XEvent *e) return; } - if (e->xbutton.button == Button2) { + if (e->xbutton.button == Button2) selpaste(NULL); - } else if (e->xbutton.button == Button1) { - if (sel.mode == SEL_READY) { - mousesel(e); - setsel(getsel(), e->xbutton.time); - } else - selclear_(NULL); - sel.mode = SEL_IDLE; - } + else if (e->xbutton.button == Button1) + mousesel(e, 1); } void @@ -650,11 +645,7 @@ bmotion(XEvent *e) return; } - if (!sel.mode) - return; - - sel.mode = SEL_READY; - mousesel(e); + mousesel(e, 0); } void From 33201ac65f74e45b4fa60822ba9a538c3cfa9b25 Mon Sep 17 00:00:00 2001 From: "Devin J. Pohly" Date: Thu, 22 Feb 2018 01:05:12 -0600 Subject: [PATCH 047/129] Move CRLF input processing into ttywrite This also allows us to remove the crlf field from the Key struct, since the only difference it made was converting "\r" to "\r\n" (which is now done automatically in ttywrite). In addition, MODE_CRLF is no longer referenced from x.c. Signed-off-by: Devin J. Pohly --- config.def.h | 423 +++++++++++++++++++++++++-------------------------- st.c | 32 +++- x.c | 6 +- 3 files changed, 240 insertions(+), 221 deletions(-) diff --git a/config.def.h b/config.def.h index 1c181ab..616616a 100644 --- a/config.def.h +++ b/config.def.h @@ -229,219 +229,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}, }; /* diff --git a/st.c b/st.c index 7d546da..3ebf8c6 100644 --- a/st.c +++ b/st.c @@ -108,6 +108,7 @@ typedef struct { static void execsh(char **); static void stty(char **); static void sigchld(int); +static void ttywriteraw(const char *, size_t); static void csidump(void); static void csihandle(void); @@ -786,13 +787,38 @@ ttyread(void) void ttywrite(const char *s, size_t n, int may_echo) { - fd_set wfd, rfd; - ssize_t r; - size_t lim = 256; + const char *next; 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 diff --git a/x.c b/x.c index 49a22e4..76fb910 100644 --- a/x.c +++ b/x.c @@ -38,10 +38,9 @@ typedef struct { KeySym k; uint mask; char *s; - /* three valued logic variables: 0 indifferent, 1 on, -1 off */ + /* 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; /* X modifiers */ @@ -1680,9 +1679,6 @@ kmap(KeySym k, uint state) 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; } From 32d3b1d00f66eda4f5446f3b32cabed2c9a77a40 Mon Sep 17 00:00:00 2001 From: "Devin J. Pohly" Date: Sun, 15 Oct 2017 20:35:48 -0500 Subject: [PATCH 048/129] Factor out equivalent code from ttyread/ttysend The echo-to-terminal portions of ttyread and ttysend were actually doing the same thing. New function twrite() now handles this. The parameter show_ctrl determines whether control characters are shown as "^A". This was the only difference between tputc and techo, and techo is now unused and removed. (This commit should not change st's behaviour.) Signed-off-by: Devin J. Pohly --- st.c | 101 +++++++++++++++++++++++------------------------------------ st.h | 2 +- 2 files changed, 41 insertions(+), 62 deletions(-) diff --git a/st.c b/st.c index 58f7941..641f896 100644 --- a/st.c +++ b/st.c @@ -161,8 +161,8 @@ static void tsetchar(Rune, Glyph *, int, int); static void tsetscroll(int, int); static void tswapscreen(void); 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); @@ -254,7 +254,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; @@ -768,38 +768,19 @@ 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); return ret; } @@ -864,27 +845,9 @@ ttywrite(const char *s, size_t n) 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; - } + if (IS_SET(MODE_ECHO)) + twrite(s, n, 1); } void @@ -2031,22 +1994,6 @@ tputtab(int n) term.c.x = LIMIT(x, 0, term.col-1); } -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) { @@ -2437,6 +2384,38 @@ tputc(Rune u) } } +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) { diff --git a/st.h b/st.h index 09473c2..3d9b6e7 100644 --- a/st.h +++ b/st.h @@ -209,7 +209,7 @@ void selnormalize(void); int selected(int, int); char *getsel(void); -size_t utf8decode(char *, Rune *, size_t); +size_t utf8decode(const char *, Rune *, size_t); size_t utf8encode(Rune, char *); void *xmalloc(size_t); From 52d6fb1ab1f7d41839edebb63c3408578cd44e3c Mon Sep 17 00:00:00 2001 From: "Devin J. Pohly" Date: Thu, 22 Feb 2018 00:42:23 -0600 Subject: [PATCH 049/129] Move terminal echo logic into st.c The only thing differentiating ttywrite and ttysend was the potential for echo; make this a parameter and remove ttysend. Signed-off-by: Devin J. Pohly --- st.c | 23 +++++++++-------------- st.h | 3 +-- x.c | 18 +++++++++--------- 3 files changed, 19 insertions(+), 25 deletions(-) diff --git a/st.c b/st.c index b7e215e..7d546da 100644 --- a/st.c +++ b/st.c @@ -784,12 +784,15 @@ ttyread(void) } 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; + if (may_echo && IS_SET(MODE_ECHO)) + twrite(s, n, 1); + /* * 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 @@ -840,14 +843,6 @@ ttywrite(const char *s, size_t n) die("write error on tty: %s\n", strerror(errno)); } -void -ttysend(char *s, size_t n) -{ - ttywrite(s, n); - if (IS_SET(MODE_ECHO)) - twrite(s, n, 1); -} - void ttyresize(int tw, int th) { @@ -1570,7 +1565,7 @@ csihandle(void) break; case 'c': /* DA -- Device Attributes */ if (csiescseq.arg[0] == 0) - ttywrite(vtiden, strlen(vtiden)); + ttywrite(vtiden, strlen(vtiden), 0); break; case 'C': /* CUF -- Cursor Forward */ case 'a': /* HPR -- Cursor Forward */ @@ -1698,7 +1693,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 */ @@ -1916,7 +1911,7 @@ iso14755(const Arg *arg) (*e != '\n' && *e != '\0')) return; - ttysend(uc, utf8encode(utf32, uc)); + ttywrite(uc, utf8encode(utf32, uc), 1); } void @@ -2129,7 +2124,7 @@ tcontrolcode(uchar ascii) case 0x99: /* TODO: SGCI */ break; case 0x9a: /* DECID -- Identify Terminal */ - ttywrite(vtiden, strlen(vtiden)); + ttywrite(vtiden, strlen(vtiden), 0); break; case 0x9b: /* TODO: CSI */ case 0x9c: /* TODO: ST */ @@ -2201,7 +2196,7 @@ eschandle(uchar ascii) } break; case 'Z': /* DECID -- Identify Terminal */ - ttywrite(vtiden, strlen(vtiden)); + ttywrite(vtiden, strlen(vtiden), 0); break; case 'c': /* RIS -- Reset to inital state */ treset(); diff --git a/st.h b/st.h index a34e31c..d7738a0 100644 --- a/st.h +++ b/st.h @@ -176,8 +176,7 @@ void tsetdirtattr(int); void ttynew(char *, char *, char **); size_t ttyread(void); void ttyresize(int, int); -void ttysend(char *, size_t); -void ttywrite(const char *, size_t); +void ttywrite(const char *, size_t, int); void resettitle(void); diff --git a/x.c b/x.c index a7f619e..49a22e4 100644 --- a/x.c +++ b/x.c @@ -390,7 +390,7 @@ mousereport(XEvent *e) return; } - ttywrite(buf, len); + ttywrite(buf, len, 0); } void @@ -408,7 +408,7 @@ bpress(XEvent *e) 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)); + ttywrite(ms->s, strlen(ms->s), 1); return; } } @@ -520,10 +520,10 @@ selnotify(XEvent *e) } if (IS_SET(MODE_BRCKTPASTE) && ofs == 0) - ttywrite("\033[200~", 6); - ttysend((char *)data, nitems * format / 8); + ttywrite("\033[200~", 6, 0); + ttywrite((char *)data, nitems * format / 8, 1); if (IS_SET(MODE_BRCKTPASTE) && rem == 0) - ttywrite("\033[201~", 6); + ttywrite("\033[201~", 6, 0); XFree(data); /* number of 32-bit chunks returned */ ofs += nitems * format / 32; @@ -1634,12 +1634,12 @@ focus(XEvent *ev) win.state |= WIN_FOCUSED; xseturgency(0); if (IS_SET(MODE_FOCUS)) - ttywrite("\033[I", 3); + ttywrite("\033[I", 3, 0); } else { XUnsetICFocus(xw.xic); win.state &= ~WIN_FOCUSED; if (IS_SET(MODE_FOCUS)) - ttywrite("\033[O", 3); + ttywrite("\033[O", 3, 0); } } @@ -1714,7 +1714,7 @@ kpress(XEvent *ev) /* 2. custom keys from config.h */ if ((customkey = kmap(ksym, e->state))) { - ttysend(customkey, strlen(customkey)); + ttywrite(customkey, strlen(customkey), 1); return; } @@ -1733,7 +1733,7 @@ kpress(XEvent *ev) len = 2; } } - ttysend(buf, len); + ttywrite(buf, len, 1); } From a5dc1b46976b2252f9d7bb68f126c4b0f351dd1a Mon Sep 17 00:00:00 2001 From: "Devin J. Pohly" Date: Sat, 24 Feb 2018 14:58:54 -0600 Subject: [PATCH 050/129] Pull term references out of xdrawcursor Gradually reducing x.c dependency on Term object. Old and new cursor glyph/position are passed to xdrawcursor. (There may be an opportunity to refactor further if we can unify "clear old cursor" and "draw new cursor" functionality.) Signed-off-by: Devin J. Pohly --- st.c | 15 ++++++++++++++- st.h | 4 +++- win.h | 2 +- x.c | 61 +++++++++++++++++++++-------------------------------------- 4 files changed, 40 insertions(+), 42 deletions(-) diff --git a/st.c b/st.c index 504239e..4bf6378 100644 --- a/st.c +++ b/st.c @@ -2544,10 +2544,23 @@ drawregion(int x1, int y1, int x2, int y2) void draw(void) { + int cx = term.c.x; + if (!xstartdraw()) return; + + /* 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--; + drawregion(0, 0, term.col, term.row); - xdrawcursor(); + 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 7026de8..27c48cf 100644 --- a/st.h +++ b/st.h @@ -82,8 +82,10 @@ typedef struct { int col; /* nb col */ Line *line; /* screen */ Line *alt; /* alternate screen */ - int *dirty; /* dirtyness of lines */ + 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 */ diff --git a/win.h b/win.h index 6e662af..7a866fd 100644 --- a/win.h +++ b/win.h @@ -25,7 +25,7 @@ enum win_mode { void xbell(void); void xclipcopy(void); -void xdrawcursor(void); +void xdrawcursor(int, int, Glyph, int, int, Glyph); void xdrawline(Line, int, int, int); void xhints(void); void xfinishdraw(void); diff --git a/x.c b/x.c index 96944ee..d205ca7 100644 --- a/x.c +++ b/x.c @@ -1387,41 +1387,26 @@ xdrawglyph(Glyph g, int x, int y) } void -xdrawcursor(void) +xdrawcursor(int cx, int cy, Glyph g, int ox, int oy, Glyph og) { - static int oldx = 0, oldy = 0; - int curx; - Glyph g = {' ', ATTR_NULL, defaultbg, defaultcs}, og; 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 (selected(oldx, oldy)) + if (selected(ox, oy)) og.mode ^= ATTR_REVERSE; - xdrawglyph(og, oldx, oldy); - - g.u = term.line[term.c.y][term.c.x].u; - g.mode |= term.line[term.c.y][term.c.x].mode & - (ATTR_BOLD | ATTR_ITALIC | ATTR_UNDERLINE | ATTR_STRUCK); + xdrawglyph(og, ox, oy); /* * Select the right color for the right mode. */ + g.mode &= ATTR_BOLD|ATTR_ITALIC|ATTR_UNDERLINE|ATTR_STRUCK|ATTR_WIDE; + g.fg = defaultbg; + g.bg = defaultcs; + if (IS_SET(MODE_REVERSE)) { g.mode |= ATTR_REVERSE; g.bg = defaultfg; - if (selected(term.c.x, term.c.y)) { + if (selected(cx, cy)) { drawcol = dc.col[defaultcs]; g.fg = defaultrcs; } else { @@ -1429,7 +1414,7 @@ xdrawcursor(void) g.fg = defaultcs; } } else { - if (selected(term.c.x, term.c.y)) { + if (selected(cx, cy)) { drawcol = dc.col[defaultrcs]; g.fg = defaultfg; g.bg = defaultrcs; @@ -1449,44 +1434,42 @@ xdrawcursor(void) 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); + xdrawglyph(g, cx, cy); break; case 3: /* Blinking Underline */ case 4: /* Steady Underline */ XftDrawRect(xw.draw, &drawcol, - borderpx + curx * win.cw, - borderpx + (term.c.y + 1) * win.ch - \ + 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 + curx * win.cw, - borderpx + term.c.y * win.ch, + borderpx + cx * win.cw, + borderpx + cy * win.ch, cursorthickness, win.ch); break; } } else { XftDrawRect(xw.draw, &drawcol, - borderpx + curx * win.cw, - borderpx + term.c.y * win.ch, + borderpx + cx * win.cw, + borderpx + cy * win.ch, win.cw - 1, 1); XftDrawRect(xw.draw, &drawcol, - borderpx + curx * win.cw, - borderpx + term.c.y * win.ch, + borderpx + cx * win.cw, + borderpx + cy * win.ch, 1, win.ch - 1); XftDrawRect(xw.draw, &drawcol, - borderpx + (curx + 1) * win.cw - 1, - borderpx + term.c.y * win.ch, + borderpx + (cx + 1) * win.cw - 1, + borderpx + cy * win.ch, 1, win.ch - 1); XftDrawRect(xw.draw, &drawcol, - borderpx + curx * win.cw, - borderpx + (term.c.y + 1) * win.ch - 1, + borderpx + cx * win.cw, + borderpx + (cy + 1) * win.ch - 1, win.cw, 1); } - oldx = curx, oldy = term.c.y; } void From a3beb626d2dae9d4d0883c7c8cb6ba58b0609105 Mon Sep 17 00:00:00 2001 From: "Devin J. Pohly" Date: Sat, 24 Feb 2018 15:32:48 -0600 Subject: [PATCH 051/129] Remove x.c dependency on term The xinit function only needs to the rows/cols, so pass those in rather than accessing term directly. With a bit of arithmetic, we are able to avoid the need for term.row and term.col in x2col, y2row, and xdrawglyphfontspecs as well, completing the removal. Term is now fully internal to st.c. Signed-off-by: Devin J. Pohly --- st.c | 22 +++++++++++++++++++++- st.h | 21 --------------------- x.c | 35 ++++++++++++++++++----------------- 3 files changed, 39 insertions(+), 39 deletions(-) diff --git a/st.c b/st.c index 4bf6378..da832ed 100644 --- a/st.c +++ b/st.c @@ -95,6 +95,26 @@ enum escape_state { ESC_DCS =128, }; +/* 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 */ + char trantbl[4]; /* charset table translation */ + int charset; /* current charset */ + int icharset; /* selected charset for sequence */ + int *tabs; +} Term; + /* CSI Escape sequence structs */ /* ESC '[' [[ [] [;]] []] */ typedef struct { @@ -181,11 +201,11 @@ static char *base64dec(const char *); static ssize_t xwrite(int, const char *, size_t); /* Globals */ -Term term; int cmdfd; pid_t pid; int oldbutton = 3; /* button event on startup: 3 = release */ +static Term term; static Selection sel; static CSIEscape csiescseq; static STREscape strescseq; diff --git a/st.h b/st.h index 27c48cf..b5bc1b5 100644 --- a/st.h +++ b/st.h @@ -76,26 +76,6 @@ typedef struct { char state; } TCursor; -/* 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 */ - char trantbl[4]; /* charset table translation */ - int charset; /* current charset */ - int icharset; /* selected charset for sequence */ - int *tabs; -} Term; - /* Purely graphic info */ typedef struct { int tw, th; /* tty width and height */ @@ -168,7 +148,6 @@ void *xrealloc(void *, size_t); char *xstrdup(char *); /* Globals */ -extern Term term; extern int cmdfd; extern pid_t pid; extern int oldbutton; diff --git a/x.c b/x.c index d205ca7..873ff08 100644 --- a/x.c +++ b/x.c @@ -130,7 +130,7 @@ 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(void); +static void xinit(int, int); static void cresize(int, int); static void xresize(int, int); static int xloadfont(Font *, FcPattern *); @@ -299,18 +299,16 @@ int x2col(int x) { x -= borderpx; - x /= win.cw; - - return LIMIT(x, 0, term.col-1); + LIMIT(x, 0, win.tw - 1); + return x / win.cw; } int y2row(int y) { y -= borderpx; - y /= win.ch; - - return LIMIT(y, 0, term.row-1); + LIMIT(y, 0, win.th - 1); + return y / win.ch; } void @@ -984,7 +982,7 @@ xunloadfonts(void) } void -xinit(void) +xinit(int cols, int rows) { XGCValues gcvalues; Cursor cursor; @@ -1009,8 +1007,8 @@ xinit(void) xloadcols(); /* adjust fixed window geometry */ - win.w = 2 * borderpx + term.col * win.cw; - win.h = 2 * borderpx + term.row * win.ch; + win.w = 2 * borderpx + cols * win.cw; + win.h = 2 * borderpx + rows * win.ch; if (xw.gm & XNegative) xw.l += DisplayWidth(xw.dpy, xw.scr) - win.w - 2; if (xw.gm & YNegative) @@ -1042,7 +1040,7 @@ xinit(void) XFillRectangle(xw.dpy, xw.buf, dc.gc, 0, 0, win.w, win.h); /* font spec buffer */ - xw.specbuf = xmalloc(term.col * sizeof(GlyphFontSpec)); + xw.specbuf = xmalloc(cols * sizeof(GlyphFontSpec)); /* Xft rendering context */ xw.draw = XftDrawCreate(xw.dpy, xw.buf, xw.vis, xw.cmap); @@ -1337,15 +1335,16 @@ xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, i /* Intelligent cleaning up of the borders. */ if (x == 0) { xclear(0, (y == 0)? 0 : winy, borderpx, - winy + win.ch + ((y >= term.row-1)? win.h : 0)); + winy + win.ch + + ((winy + win.ch >= borderpx + win.th)? win.h : 0)); } - if (x + charlen >= term.col) { + if (winx + width >= borderpx + win.tw) { xclear(winx + width, (y == 0)? 0 : winy, win.w, - ((y >= term.row-1)? win.h : (winy + win.ch))); + ((winy + win.ch >= borderpx + win.th)? win.h : (winy + win.ch))); } if (y == 0) xclear(winx, 0, winx + width, borderpx); - if (y == term.row-1) + 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. */ @@ -1930,8 +1929,10 @@ main(int argc, char *argv[]) } setlocale(LC_CTYPE, ""); XSetLocaleModifiers(""); - tnew(MAX(cols, 1), MAX(rows, 1)); - xinit(); + cols = MAX(cols, 1); + rows = MAX(rows, 1); + tnew(cols, rows); + xinit(cols, rows); xsetenv(); selinit(); run(); From 30683c70ab62fd37b5921cf72077b9aef2cb842e Mon Sep 17 00:00:00 2001 From: "Devin J. Pohly" Date: Sat, 24 Feb 2018 16:16:12 -0600 Subject: [PATCH 052/129] Limit usage of extern to config.h globals Prefer passing arguments to declaring external global variables. The only remaining usage of extern is for config.h variables which are needed in st.c instead of x.c (where it is now included). Signed-off-by: Devin J. Pohly --- config.def.h | 2 +- st.c | 29 +++++++++++++++++------------ st.h | 9 ++------- x.c | 16 +++++++++------- 4 files changed, 29 insertions(+), 27 deletions(-) diff --git a/config.def.h b/config.def.h index 616616a..82b1b09 100644 --- a/config.def.h +++ b/config.def.h @@ -16,7 +16,7 @@ static int borderpx = 2; * 4: value of shell in /etc/passwd * 5: value of shell in config.h */ -char *shell = "/bin/sh"; +static char *shell = "/bin/sh"; char *utmp = NULL; char *stty_args = "stty raw pass8 nl -echo -iexten -cstopb 38400"; diff --git a/st.c b/st.c index da832ed..ce32cc0 100644 --- a/st.c +++ b/st.c @@ -136,8 +136,7 @@ typedef struct { int narg; /* nb of args */ } STREscape; - -static void execsh(char **); +static void execsh(char *, char **); static void stty(char **); static void sigchld(int); static void ttywriteraw(const char *, size_t); @@ -201,15 +200,13 @@ static char *base64dec(const char *); static ssize_t xwrite(int, const char *, size_t); /* Globals */ -int cmdfd; -pid_t pid; -int oldbutton = 3; /* button event on startup: 3 = release */ - static Term term; static Selection sel; static CSIEscape csiescseq; static STREscape strescseq; static int iofd = 1; +static int cmdfd; +static pid_t pid; static uchar utfbyte[UTF_SIZ + 1] = {0x80, 0, 0xC0, 0xE0, 0xF0}; static uchar utfmask[UTF_SIZ + 1] = {0xC0, 0x80, 0xE0, 0xF0, 0xF8}; @@ -659,7 +656,7 @@ die(const char *errstr, ...) } void -execsh(char **args) +execsh(char *cmd, char **args) { char *sh, *prog; const struct passwd *pw; @@ -673,7 +670,7 @@ execsh(char **args) } if ((sh = getenv("SHELL")) == NULL) - sh = (pw->pw_shell[0]) ? pw->pw_shell : shell; + sh = (pw->pw_shell[0]) ? pw->pw_shell : cmd; if (args) prog = args[0]; @@ -745,8 +742,8 @@ stty(char **args) perror("Couldn't call stty"); } -void -ttynew(char *line, char *out, char **args) +int +ttynew(char *line, char *cmd, char *out, char **args) { int m, s; @@ -765,7 +762,7 @@ ttynew(char *line, char *out, char **args) die("open line failed: %s\n", strerror(errno)); dup2(cmdfd, 0); stty(args); - return; + return cmdfd; } /* seems to work fine on linux, openbsd and freebsd */ @@ -786,7 +783,7 @@ ttynew(char *line, char *out, char **args) die("ioctl TIOCSCTTY failed: %s\n", strerror(errno)); close(s); close(m); - execsh(args); + execsh(cmd, args); break; default: close(s); @@ -794,6 +791,7 @@ ttynew(char *line, char *out, char **args) signal(SIGCHLD, sigchld); break; } + return cmdfd; } size_t @@ -916,6 +914,13 @@ ttyresize(int tw, int th) fprintf(stderr, "Couldn't set window size: %s\n", strerror(errno)); } +void +ttyhangup() +{ + /* Send SIGHUP to shell */ + kill(pid, SIGHUP); +} + int tattrset(int attr) { diff --git a/st.h b/st.h index b5bc1b5..0a7472b 100644 --- a/st.h +++ b/st.h @@ -125,7 +125,8 @@ int tattrset(int); void tnew(int, int); void tresize(int, int); void tsetdirtattr(int); -void ttynew(char *, char *, char **); +void ttyhangup(void); +int ttynew(char *, char *, char *, char **); size_t ttyread(void); void ttyresize(int, int); void ttywrite(const char *, size_t, int); @@ -147,13 +148,7 @@ void *xmalloc(size_t); void *xrealloc(void *, size_t); char *xstrdup(char *); -/* Globals */ -extern int cmdfd; -extern pid_t pid; -extern int oldbutton; - /* config.h globals */ -extern char *shell; extern char *utmp; extern char *stty_args; extern char *vtiden; diff --git a/x.c b/x.c index 873ff08..970d6dd 100644 --- a/x.c +++ b/x.c @@ -227,6 +227,8 @@ 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) { @@ -1733,8 +1735,7 @@ cmessage(XEvent *e) win.mode &= ~MODE_FOCUSED; } } else if (e->xclient.data.l[0] == xw.wmdeletewin) { - /* Send SIGHUP to shell */ - kill(pid, SIGHUP); + ttyhangup(); exit(0); } } @@ -1755,6 +1756,7 @@ run(void) 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; @@ -1774,7 +1776,7 @@ run(void) } } while (ev.type != MapNotify); - ttynew(opt_line, opt_io, opt_cmd); + ttyfd = ttynew(opt_line, shell, opt_io, opt_cmd); cresize(w, h); clock_gettime(CLOCK_MONOTONIC, &last); @@ -1782,15 +1784,15 @@ run(void) for (xev = actionfps;;) { FD_ZERO(&rfd); - FD_SET(cmdfd, &rfd); + FD_SET(ttyfd, &rfd); FD_SET(xfd, &rfd); - if (pselect(MAX(xfd, cmdfd)+1, &rfd, NULL, NULL, tv, NULL) < 0) { + 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(cmdfd, &rfd)) { + if (FD_ISSET(ttyfd, &rfd)) { ttyread(); if (blinktimeout) { blinkset = tattrset(ATTR_BLINK); @@ -1834,7 +1836,7 @@ run(void) if (xev && !FD_ISSET(xfd, &rfd)) xev--; - if (!FD_ISSET(cmdfd, &rfd) && !FD_ISSET(xfd, &rfd)) { + if (!FD_ISSET(ttyfd, &rfd) && !FD_ISSET(xfd, &rfd)) { if (blinkset) { if (TIMEDIFF(now, lastblink) \ > blinktimeout) { From e0215d53770a9b6bc6e5d7b9a603ecd34dbd7100 Mon Sep 17 00:00:00 2001 From: "Devin J. Pohly" Date: Sat, 24 Feb 2018 16:32:20 -0600 Subject: [PATCH 053/129] Reduce visibility wherever possible When possible, declare functions/variables static and move struct definitions out of headers. In order to allow utf8decode to become internal, use codepoint for DECSCUSR extension directly. Signed-off-by: Devin J. Pohly --- st.c | 31 ++++++++++++++++++++++++++++++- st.h | 40 ---------------------------------------- win.h | 1 - x.c | 15 +++++++++++++-- 4 files changed, 43 insertions(+), 44 deletions(-) diff --git a/st.c b/st.c index ce32cc0..f46aab6 100644 --- a/st.c +++ b/st.c @@ -36,6 +36,7 @@ /* Arbitrary sizes */ #define UTF_INVALID 0xFFFD +#define UTF_SIZ 4 #define ESC_BUF_SIZ (128*UTF_SIZ) #define ESC_ARG_SIZ 16 #define STR_BUF_SIZ ESC_BUF_SIZ @@ -95,6 +96,31 @@ enum escape_state { ESC_DCS =128, }; +typedef struct { + Glyph attr; /* current char attributes */ + int x; + int y; + char state; +} TCursor; + +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; + + int alt; +} Selection; + /* Internal representation of the screen */ typedef struct { int row; /* nb row */ @@ -187,15 +213,18 @@ static void tstrsequence(uchar); static void drawregion(int, int, int, int); +static void selnormalize(void); static void selscroll(int, int); static void selsnap(int *, int *, int); +static size_t utf8decode(const char *, Rune *, size_t); static Rune utf8decodebyte(char, size_t *); static char utf8encodebyte(Rune, size_t); -static 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); diff --git a/st.h b/st.h index 0a7472b..1015fc6 100644 --- a/st.h +++ b/st.h @@ -1,8 +1,5 @@ /* See LICENSE for license details. */ -/* Arbitrary sizes */ -#define UTF_SIZ 4 - /* macros */ #define MIN(a, b) ((a) < (b) ? (a) : (b)) #define MAX(a, b) ((a) < (b) ? (b) : (a)) @@ -69,41 +66,6 @@ typedef struct { typedef Glyph *Line; -typedef struct { - Glyph attr; /* current char attributes */ - int x; - int y; - char state; -} TCursor; - -/* 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 mode; /* window state/mode flags */ - int cursor; /* cursor style */ -} TermWindow; - -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; - - int alt; -} Selection; - typedef union { int i; uint ui; @@ -137,11 +99,9 @@ void selclear(void); void selinit(void); void selstart(int, int, int); void selextend(int, int, int, int); -void selnormalize(void); int selected(int, int); char *getsel(void); -size_t utf8decode(const char *, Rune *, size_t); size_t utf8encode(Rune, char *); void *xmalloc(size_t); diff --git a/win.h b/win.h index 7a866fd..31f327d 100644 --- a/win.h +++ b/win.h @@ -27,7 +27,6 @@ void xbell(void); void xclipcopy(void); void xdrawcursor(int, int, Glyph, int, int, Glyph); void xdrawline(Line, int, int, int); -void xhints(void); void xfinishdraw(void); void xloadcols(void); int xsetcolorname(int, const char *); diff --git a/x.c b/x.c index 970d6dd..f7b0528 100644 --- a/x.c +++ b/x.c @@ -75,6 +75,15 @@ 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 mode; /* window state/mode flags */ + int cursor; /* cursor style */ +} TermWindow; + typedef struct { Display *dpy; Colormap cmap; @@ -133,6 +142,8 @@ 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 *); @@ -1430,8 +1441,8 @@ xdrawcursor(int cx, int cy, Glyph g, int ox, int oy, Glyph og) /* draw the new one */ if (IS_SET(MODE_FOCUSED)) { switch (win.cursor) { - case 7: /* st extension: snowman */ - utf8decode("☃", &g.u, UTF_SIZ); + case 7: /* st extension: snowman (U+2603) */ + g.u = 0x2603; case 0: /* Blinking Block */ case 1: /* Blinking Block (Default) */ case 2: /* Steady Block */ From 05c66cb37d9ff278a3e0c45682c4b5e7945deb42 Mon Sep 17 00:00:00 2001 From: "Devin J. Pohly" Date: Fri, 23 Feb 2018 14:16:52 -0600 Subject: [PATCH 054/129] Split mode bits between Term and TermWindow Moves the mode bits used by x.c from Term to TermWindow, absorbing UI/input-related mode bits (visible/focused/numlock) along the way. This is gradually reducing external references to Term. Since TermWindow is already internal to x.c, we add xsetmode() to allow st to modify window bits in accordance with escape sequences. IS_SET() is redefined accordingly (term.mode in st.c, win.mode in x.c). Signed-off-by: Devin J. Pohly --- st.c | 64 +++++++++++++++++++++++++++++------------------------------ st.h | 33 +----------------------------- win.h | 24 ++++++++++++++++++++++ x.c | 50 ++++++++++++++++++++++++++++------------------ 4 files changed, 88 insertions(+), 83 deletions(-) diff --git a/st.c b/st.c index 3ebf8c6..01791a5 100644 --- a/st.c +++ b/st.c @@ -42,6 +42,7 @@ #define STR_ARG_SIZ ESC_ARG_SIZ /* macros */ +#define IS_SET(flag) ((term.mode & (flag)) != 0) #define NUMMAXLEN(x) ((int)(sizeof(x) * 2.56 + 0.5) + 1) #define ISCONTROLC0(c) (BETWEEN(c, 0, 0x1f) || (c) == '\177') #define ISCONTROLC1(c) (BETWEEN(c, 0x80, 0x9f)) @@ -51,6 +52,17 @@ /* constants */ #define ISO14755CMD "dmenu -w \"$WINDOWID\" -p codepoint: ': /* DECPNM -- Normal keypad */ - term.mode &= ~MODE_APPKEYPAD; + xsetmode(0, MODE_APPKEYPAD); break; case '7': /* DECSC -- Save Cursor */ tcursor(CURSOR_SAVE); @@ -2526,9 +2532,3 @@ redraw(void) tfulldirt(); draw(); } - -void -numlock(const Arg *dummy) -{ - term.numlock ^= 1; -} diff --git a/st.h b/st.h index d7738a0..3382d61 100644 --- a/st.h +++ b/st.h @@ -13,7 +13,6 @@ #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))) @@ -37,34 +36,6 @@ enum glyph_attribute { ATTR_BOLD_FAINT = ATTR_BOLD | ATTR_FAINT, }; -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 selection_mode { SEL_IDLE = 0, SEL_EMPTY = 1, @@ -120,7 +91,6 @@ 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; @@ -130,7 +100,7 @@ typedef struct { int w, h; /* window width and height */ int ch; /* char height */ int cw; /* char width */ - char state; /* focus, redraw, visible */ + int mode; /* window state/mode flags */ int cursor; /* cursor style */ } TermWindow; @@ -163,7 +133,6 @@ void die(const char *, ...); void redraw(void); void iso14755(const Arg *); -void numlock(const Arg *); void printscreen(const Arg *); void printsel(const Arg *); void sendbreak(const Arg *); diff --git a/win.h b/win.h index 123662e..1e08b16 100644 --- a/win.h +++ b/win.h @@ -1,5 +1,28 @@ /* 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, +}; + void draw(void); void drawregion(int, int, int, int); @@ -10,5 +33,6 @@ 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 *); diff --git a/x.c b/x.c index 76fb910..c5826cf 100644 --- a/x.c +++ b/x.c @@ -51,6 +51,7 @@ typedef struct { /* 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 *); @@ -64,6 +65,7 @@ static void zoomreset(const Arg *); #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) @@ -196,11 +198,6 @@ static XWindow xw; static XSelection xsel; static TermWindow win; -enum window_state { - WIN_VISIBLE = 1, - WIN_FOCUSED = 2 -}; - /* Font Ring Cache */ enum { FRC_NORMAL, @@ -263,6 +260,12 @@ selpaste(const Arg *dummy) xw.win, CurrentTime); } +void +numlock(const Arg *dummy) +{ + win.mode ^= MODE_NUMLOCK; +} + void zoom(const Arg *arg) { @@ -1090,6 +1093,7 @@ xinit(void) 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(); @@ -1319,14 +1323,13 @@ xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, i fg = &revfg; } - if (base.mode & ATTR_REVERSE) { temp = fg; fg = bg; bg = temp; } - if (base.mode & ATTR_BLINK && term.mode & MODE_BLINK) + if (base.mode & ATTR_BLINK && win.mode & MODE_BLINK) fg = bg; if (base.mode & ATTR_INVISIBLE) @@ -1440,7 +1443,7 @@ xdrawcursor(void) return; /* draw the new one */ - if (win.state & WIN_FOCUSED) { + if (IS_SET(MODE_FOCUSED)) { switch (win.cursor) { case 7: /* st extension: snowman */ utf8decode("☃", &g.u, UTF_SIZ); @@ -1527,7 +1530,7 @@ drawregion(int x1, int y1, int x2, int y2) Glyph base, new; XftGlyphFontSpec *specs; - if (!(win.state & WIN_VISIBLE)) + if (!(IS_SET(MODE_VISIBLE))) return; for (y = y1; y < y2; y++) { @@ -1575,13 +1578,13 @@ visibility(XEvent *ev) { XVisibilityEvent *e = &ev->xvisibility; - MODBIT(win.state, e->state != VisibilityFullyObscured, WIN_VISIBLE); + MODBIT(win.mode, e->state != VisibilityFullyObscured, MODE_VISIBLE); } void unmap(XEvent *ev) { - win.state &= ~WIN_VISIBLE; + win.mode &= ~MODE_VISIBLE; } void @@ -1591,6 +1594,15 @@ xsetpointermotion(int set) 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) { @@ -1614,7 +1626,7 @@ xseturgency(int add) void xbell(void) { - if (!(win.state & WIN_FOCUSED)) + if (!(IS_SET(MODE_FOCUSED))) xseturgency(1); if (bellvolume) XkbBell(xw.dpy, xw.win, bellvolume, (Atom)NULL); @@ -1630,13 +1642,13 @@ focus(XEvent *ev) if (ev->type == FocusIn) { XSetICFocus(xw.xic); - win.state |= WIN_FOCUSED; + win.mode |= MODE_FOCUSED; xseturgency(0); if (IS_SET(MODE_FOCUS)) ttywrite("\033[I", 3, 0); } else { XUnsetICFocus(xw.xic); - win.state &= ~WIN_FOCUSED; + win.mode &= ~MODE_FOCUSED; if (IS_SET(MODE_FOCUS)) ttywrite("\033[O", 3, 0); } @@ -1673,7 +1685,7 @@ kmap(KeySym k, uint state) if (IS_SET(MODE_APPKEYPAD) ? kp->appkey < 0 : kp->appkey > 0) continue; - if (term.numlock && kp->appkey == 2) + if (IS_SET(MODE_NUMLOCK) && kp->appkey == 2) continue; if (IS_SET(MODE_APPCURSOR) ? kp->appcursor < 0 : kp->appcursor > 0) @@ -1742,10 +1754,10 @@ cmessage(XEvent *e) */ if (e->xclient.message_type == xw.xembed && e->xclient.format == 32) { if (e->xclient.data.l[1] == XEMBED_FOCUS_IN) { - win.state |= WIN_FOCUSED; + win.mode |= MODE_FOCUSED; xseturgency(0); } else if (e->xclient.data.l[1] == XEMBED_FOCUS_OUT) { - win.state &= ~WIN_FOCUSED; + win.mode &= ~MODE_FOCUSED; } } else if (e->xclient.data.l[0] == xw.wmdeletewin) { /* Send SIGHUP to shell */ @@ -1810,7 +1822,7 @@ run(void) if (blinktimeout) { blinkset = tattrset(ATTR_BLINK); if (!blinkset) - MODBIT(term.mode, 0, MODE_BLINK); + MODBIT(win.mode, 0, MODE_BLINK); } } @@ -1825,7 +1837,7 @@ run(void) dodraw = 0; if (blinktimeout && TIMEDIFF(now, lastblink) > blinktimeout) { tsetdirtattr(ATTR_BLINK); - term.mode ^= MODE_BLINK; + win.mode ^= MODE_BLINK; lastblink = now; dodraw = 1; } From 403c57ebb5b3745ff93e49b87e526c49dc59a5b9 Mon Sep 17 00:00:00 2001 From: "Devin J. Pohly" Date: Sat, 24 Feb 2018 16:45:42 -0600 Subject: [PATCH 055/129] Clean up #includes Signed-off-by: Devin J. Pohly --- st.c | 7 ------- st.h | 3 +++ x.c | 3 +-- 3 files changed, 4 insertions(+), 9 deletions(-) diff --git a/st.c b/st.c index f46aab6..543c615 100644 --- a/st.c +++ b/st.c @@ -3,24 +3,17 @@ #include #include #include -#include #include #include #include #include #include #include -#include #include #include -#include -#include #include #include -#include -#include #include -#include #include #include "st.h" diff --git a/st.h b/st.h index 1015fc6..dac64d8 100644 --- a/st.h +++ b/st.h @@ -1,5 +1,8 @@ /* See LICENSE for license details. */ +#include +#include + /* macros */ #define MIN(a, b) ((a) < (b) ? (a) : (b)) #define MAX(a, b) ((a) < (b) ? (b) : (a)) diff --git a/x.c b/x.c index f7b0528..d0acfee 100644 --- a/x.c +++ b/x.c @@ -1,15 +1,14 @@ /* See LICENSE for license details. */ #include +#include #include #include -#include #include #include #include #include #include #include -#include #include #include #include From 88d8293fb4ba150a5f19d58d133b5db93d9dcfa5 Mon Sep 17 00:00:00 2001 From: "Devin J. Pohly" Date: Sat, 24 Feb 2018 14:53:23 -0600 Subject: [PATCH 056/129] Move win-agnostic parts of draw/drawregion to st.c Introduces three functions to encapsulate X-specific behavior: * xdrawline: draws a portion of a single line (used by drawregion) * xbegindraw: called to prepare for drawing (will be useful for e.g. Wayland) and returns true if drawing should happen * xfinishdraw: called to finish drawing (used by draw) Signed-off-by: Devin J. Pohly --- st.c | 25 +++++++++++++++++++ st.h | 1 + win.h | 7 +++--- x.c | 79 ++++++++++++++++++++++++++--------------------------------- 4 files changed, 65 insertions(+), 47 deletions(-) diff --git a/st.c b/st.c index 01791a5..504239e 100644 --- a/st.c +++ b/st.c @@ -166,6 +166,8 @@ static int32_t tdefcolor(int *, int *, int); static void tdeftran(char); static void tstrsequence(uchar); +static void drawregion(int, int, int, int); + static void selscroll(int, int); static void selsnap(int *, int *, int); @@ -2526,6 +2528,29 @@ resettitle(void) xsettitle(NULL); } +void +drawregion(int x1, int y1, int x2, int y2) +{ + int y; + for (y = y1; y < y2; y++) { + if (!term.dirty[y]) + continue; + + term.dirty[y] = 0; + xdrawline(term.line[y], x1, y, x2); + } +} + +void +draw(void) +{ + if (!xstartdraw()) + return; + drawregion(0, 0, term.col, term.row); + xdrawcursor(); + xfinishdraw(); +} + void redraw(void) { diff --git a/st.h b/st.h index 3382d61..7026de8 100644 --- a/st.h +++ b/st.h @@ -131,6 +131,7 @@ typedef union { void die(const char *, ...); void redraw(void); +void draw(void); void iso14755(const Arg *); void printscreen(const Arg *); diff --git a/win.h b/win.h index 1e08b16..6e662af 100644 --- a/win.h +++ b/win.h @@ -23,12 +23,12 @@ enum win_mode { |MODE_MOUSEMANY, }; -void draw(void); -void drawregion(int, int, int, int); - void xbell(void); void xclipcopy(void); +void xdrawcursor(void); +void xdrawline(Line, int, int, int); void xhints(void); +void xfinishdraw(void); void xloadcols(void); int xsetcolorname(int, const char *); void xsettitle(char *); @@ -36,3 +36,4 @@ 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 index c5826cf..96944ee 100644 --- a/x.c +++ b/x.c @@ -129,7 +129,6 @@ 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 void xdrawcursor(void); static int xgeommasktogravity(int); static void xinit(void); static void cresize(int, int); @@ -1512,59 +1511,51 @@ xsettitle(char *p) XFree(prop.value); } -void -draw(void) +int +xstartdraw(void) { - drawregion(0, 0, term.col, term.row); - 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); + return IS_SET(MODE_VISIBLE); } void -drawregion(int x1, int y1, int x2, int y2) +xdrawline(Line line, int x1, int y1, int x2) { - int i, x, y, ox, numspecs; + int i, x, ox, numspecs; Glyph base, new; - XftGlyphFontSpec *specs; + XftGlyphFontSpec *specs = xw.specbuf; - if (!(IS_SET(MODE_VISIBLE))) - return; - - for (y = y1; y < y2; y++) { - if (!term.dirty[y]) + 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; - - term.dirty[y] = 0; - - specs = xw.specbuf; - numspecs = xmakeglyphfontspecs(specs, &term.line[y][x1], x2 - x1, x1, y); - - i = ox = 0; - for (x = x1; x < x2 && i < numspecs; x++) { - new = term.line[y][x]; - if (new.mode == ATTR_WDUMMY) - continue; - if (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 (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; } - if (i > 0) - xdrawglyphfontspecs(specs, base, i, ox, y); + i++; } - xdrawcursor(); + 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 From 20e0da7f14cc5f30863e0b8014fa223fbaff1e30 Mon Sep 17 00:00:00 2001 From: "Devin J. Pohly" Date: Sat, 24 Feb 2018 17:09:13 -0600 Subject: [PATCH 057/129] General cleanup Simplifies logic in a couple places and removes a redundant function call. Signed-off-by: Devin J. Pohly --- st.c | 1 - x.c | 46 +++++++++++++++++++++------------------------- 2 files changed, 21 insertions(+), 26 deletions(-) diff --git a/st.c b/st.c index 543c615..75c3dd1 100644 --- a/st.c +++ b/st.c @@ -1693,7 +1693,6 @@ csihandle(void) tputtab(csiescseq.arg[0]); break; case 'J': /* ED -- Clear screen */ - selclear(); switch (csiescseq.arg[0]) { case 0: /* below */ tclearregion(term.c.x, term.c.y, term.col-1, term.c.y); diff --git a/x.c b/x.c index d0acfee..f005687 100644 --- a/x.c +++ b/x.c @@ -149,8 +149,8 @@ static void xunloadfont(Font *); static void xunloadfonts(void); static void xsetenv(void); static void xseturgency(int); -static int x2col(int); -static int y2row(int); +static int evcol(XEvent *); +static int evrow(XEvent *); static void expose(XEvent *); static void visibility(XEvent *); @@ -308,17 +308,17 @@ zoomreset(const Arg *arg) } int -x2col(int x) +evcol(XEvent *e) { - x -= borderpx; + int x = e->xbutton.x - borderpx; LIMIT(x, 0, win.tw - 1); return x / win.cw; } int -y2row(int y) +evrow(XEvent *e) { - y -= borderpx; + int y = e->xbutton.y - borderpx; LIMIT(y, 0, win.th - 1); return y / win.ch; } @@ -335,7 +335,7 @@ mousesel(XEvent *e, int done) break; } } - selextend(x2col(e->xbutton.x), y2row(e->xbutton.y), seltype, done); + selextend(evcol(e), evrow(e), seltype, done); if (done) setsel(getsel(), e->xbutton.time); } @@ -343,9 +343,8 @@ mousesel(XEvent *e, int done) void mousereport(XEvent *e) { - int x = x2col(e->xbutton.x), y = y2row(e->xbutton.y), - button = e->xbutton.button, state = e->xbutton.state, - len; + int len, x = evcol(e), y = evrow(e), + button = e->xbutton.button, state = e->xbutton.state; char buf[40]; static int ox, oy; @@ -440,7 +439,7 @@ bpress(XEvent *e) xsel.tclick2 = xsel.tclick1; xsel.tclick1 = now; - selstart(x2col(e->xbutton.x), y2row(e->xbutton.y), snap); + selstart(evcol(e), evrow(e), snap); } } @@ -464,18 +463,16 @@ selnotify(XEvent *e) ulong nitems, ofs, rem; int format; uchar *data, *last, *repl; - Atom type, incratom, property; + Atom type, incratom, property = None; incratom = XInternAtom(xw.dpy, "INCR", 0); ofs = 0; - if (e->type == SelectionNotify) { + if (e->type == SelectionNotify) property = e->xselection.property; - } else if(e->type == PropertyNotify) { + else if (e->type == PropertyNotify) property = e->xproperty.atom; - } else { - return; - } + if (property == None) return; @@ -625,7 +622,7 @@ setsel(char *str, Time t) XSetSelectionOwner(xw.dpy, XA_PRIMARY, xw.win, t); if (XGetSelectionOwner(xw.dpy, XA_PRIMARY) != xw.win) - selclear_(NULL); + selclear(); } void @@ -1407,12 +1404,13 @@ xdrawcursor(int cx, int cy, Glyph g, int ox, int oy, Glyph og) 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; - g.fg = defaultbg; - g.bg = defaultcs; if (IS_SET(MODE_REVERSE)) { g.mode |= ATTR_REVERSE; @@ -1426,17 +1424,15 @@ xdrawcursor(int cx, int cy, Glyph g, int ox, int oy, Glyph og) } } else { if (selected(cx, cy)) { - drawcol = dc.col[defaultrcs]; g.fg = defaultfg; g.bg = defaultrcs; } else { - drawcol = dc.col[defaultcs]; + g.fg = defaultbg; + g.bg = defaultcs; } + drawcol = dc.col[g.bg]; } - if (IS_SET(MODE_HIDE)) - return; - /* draw the new one */ if (IS_SET(MODE_FOCUSED)) { switch (win.cursor) { From 8b8255ac0e188445f6904ff16272e9e93093cbde Mon Sep 17 00:00:00 2001 From: Hiltjo Posthuma Date: Fri, 9 Mar 2018 15:35:34 +0100 Subject: [PATCH 058/129] regression: include termios.h for tcsendbreak etc --- st.c | 1 + 1 file changed, 1 insertion(+) diff --git a/st.c b/st.c index 75c3dd1..65a0cb6 100644 --- a/st.c +++ b/st.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include From b81888ee7d95d9ecb7b1749630b09a96065a8fea Mon Sep 17 00:00:00 2001 From: Hiltjo Posthuma Date: Fri, 9 Mar 2018 15:36:25 +0100 Subject: [PATCH 059/129] xhints: no need to initialize sizeh --- x.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x.c b/x.c index f005687..537322b 100644 --- a/x.c +++ b/x.c @@ -780,7 +780,7 @@ xhints(void) XClassHint class = {opt_name ? opt_name : termname, opt_class ? opt_class : termname}; XWMHints wm = {.flags = InputHint, .input = 1}; - XSizeHints *sizeh = NULL; + XSizeHints *sizeh; sizeh = XAllocSizeHints(); From c5ba9c025b7ebc34979e839453528f6e4a18712d Mon Sep 17 00:00:00 2001 From: Hiltjo Posthuma Date: Fri, 9 Mar 2018 15:36:38 +0100 Subject: [PATCH 060/129] use math.h for ceilf --- x.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x.c b/x.c index 537322b..d43a529 100644 --- a/x.c +++ b/x.c @@ -1,5 +1,6 @@ /* See LICENSE for license details. */ #include +#include #include #include #include @@ -901,7 +902,6 @@ xloadfonts(char *fontstr, double fontsize) { FcPattern *pattern; double fontval; - float ceilf(float); if (fontstr[0] == '-') { pattern = XftXlfdParse(fontstr, False, False); From 49a4f91fc5caf4b8b64f2b73a6be506fa06917b9 Mon Sep 17 00:00:00 2001 From: Hiltjo Posthuma Date: Wed, 14 Mar 2018 19:50:37 +0100 Subject: [PATCH 061/129] bump version to 0.8 --- config.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config.mk b/config.mk index 0aceec4..b2eac10 100644 --- a/config.mk +++ b/config.mk @@ -1,5 +1,5 @@ # st version -VERSION = 0.7 +VERSION = 0.8 # Customize below to fit your system From 0f245dfeb9bb4e87a005da2ecdcd7a88ba6e7f32 Mon Sep 17 00:00:00 2001 From: Hiltjo Posthuma Date: Wed, 14 Mar 2018 19:54:50 +0100 Subject: [PATCH 062/129] Makefile: add all files to make dist --- Makefile | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index c678ead..0b3cecd 100644 --- a/Makefile +++ b/Makefile @@ -34,7 +34,9 @@ clean: dist: clean mkdir -p st-$(VERSION) - cp -R LICENSE Makefile README config.mk config.def.h st.info st.1 arg.h $(SRC) 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) From a712c2dd1815f83a56be33e8055eee29e05dfef7 Mon Sep 17 00:00:00 2001 From: Hiltjo Posthuma Date: Wed, 14 Mar 2018 20:00:35 +0100 Subject: [PATCH 063/129] update LICENSE: major contributors --- LICENSE | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/LICENSE b/LICENSE index fa0c63e..84c4d19 100644 --- a/LICENSE +++ b/LICENSE @@ -1,8 +1,11 @@ MIT/X Consortium License +© 2014-2018 Hiltjo Posthuma +© 2018 Devin J. Pohly +© 2017-2017 Quentin Rameau © 2009-2012 Aurélien APTEL © 2009 Anselm R Garbe -© 2012-2016 Roberto E. Vargas Caballero +© 2012-2017 Roberto E. Vargas Caballero © 2012-2016 Christoph Lohmann <20h at r-36 dot net> © 2013 Eon S. Jeon © 2013 Alexander Sedov From 8ab629031bd958d93deee9203fea32c38fe8ac30 Mon Sep 17 00:00:00 2001 From: Hiltjo Posthuma Date: Wed, 14 Mar 2018 20:06:42 +0100 Subject: [PATCH 064/129] LICENSE: fix a few years --- LICENSE | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/LICENSE b/LICENSE index 84c4d19..c356c39 100644 --- a/LICENSE +++ b/LICENSE @@ -2,15 +2,15 @@ MIT/X Consortium License © 2014-2018 Hiltjo Posthuma © 2018 Devin J. Pohly -© 2017-2017 Quentin Rameau +© 2014-2017 Quentin Rameau © 2009-2012 Aurélien APTEL -© 2009 Anselm R Garbe +© 2008-2017 Anselm R Garbe © 2012-2017 Roberto E. Vargas Caballero © 2012-2016 Christoph Lohmann <20h at r-36 dot net> © 2013 Eon S. Jeon © 2013 Alexander Sedov © 2013 Mark Edgar -© 2013 Eric Pruitt +© 2013-2014 Eric Pruitt © 2013 Michael Forney © 2013-2014 Markus Teich © 2014-2015 Laslo Hunhold From e7ef3c4ce95a21cfcd0988d493f636e1d0115871 Mon Sep 17 00:00:00 2001 From: Quentin Rameau Date: Fri, 16 Mar 2018 15:03:10 +0100 Subject: [PATCH 065/129] Fix regression from 69e32a6 when setting title. --- x.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x.c b/x.c index d43a529..06e53d3 100644 --- a/x.c +++ b/x.c @@ -1492,7 +1492,7 @@ void xsettitle(char *p) { XTextProperty prop; - DEFAULT(p, "st"); + DEFAULT(p, opt_title); Xutf8TextListToTextProperty(xw.dpy, &p, 1, XUTF8StringStyle, &prop); From 0b507bb73138c636fd0ad6f2321624aae1346d58 Mon Sep 17 00:00:00 2001 From: Quentin Rameau Date: Fri, 16 Mar 2018 16:19:18 +0100 Subject: [PATCH 066/129] Fix title initialization --- x.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/x.c b/x.c index 06e53d3..d0b26ac 100644 --- a/x.c +++ b/x.c @@ -1929,12 +1929,12 @@ main(int argc, char *argv[]) } ARGEND; run: - if (argc > 0) { - /* eat all remaining arguments */ + if (argc > 0) /* eat all remaining arguments */ opt_cmd = argv; - if (!opt_title && !opt_line) - opt_title = basename(xstrdup(argv[0])); - } + + if (!opt_title) + opt_title = (opt_line || !opt_cmd) ? "st" : opt_cmd[0]; + setlocale(LC_CTYPE, ""); XSetLocaleModifiers(""); cols = MAX(cols, 1); From 7648697f711d5ae336af142e9cd464d943341b24 Mon Sep 17 00:00:00 2001 From: Hiltjo Posthuma Date: Fri, 16 Mar 2018 16:45:58 +0100 Subject: [PATCH 067/129] minor code-style: whitespace fixes --- st.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/st.c b/st.c index 65a0cb6..581647b 100644 --- a/st.c +++ b/st.c @@ -740,7 +740,6 @@ sigchld(int a) exit(0); } - void stty(char **args) { @@ -762,7 +761,7 @@ stty(char **args) } *q = '\0'; if (system(cmd) != 0) - perror("Couldn't call stty"); + perror("Couldn't call stty"); } int From 5345db3c9be1a22ca19202035b881b951c2f0f9e Mon Sep 17 00:00:00 2001 From: Hiltjo Posthuma Date: Sat, 17 Mar 2018 13:48:10 +0100 Subject: [PATCH 068/129] clipcopy: no need to check for free(NULL), set to NULL after free --- x.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/x.c b/x.c index d0b26ac..12bc86b 100644 --- a/x.c +++ b/x.c @@ -245,8 +245,8 @@ clipcopy(const Arg *dummy) { Atom clipboard; - if (xsel.clipboard != NULL) - free(xsel.clipboard); + free(xsel.clipboard); + xsel.clipboard = NULL; if (xsel.primary != NULL) { xsel.clipboard = xstrdup(xsel.primary); From 6ac8c8aa50d521f82d491ab54eb972660fdf3207 Mon Sep 17 00:00:00 2001 From: Hiltjo Posthuma Date: Sat, 17 Mar 2018 13:48:29 +0100 Subject: [PATCH 069/129] selextend: clarify: !sel.mode == SEL_IDLE --- st.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/st.c b/st.c index 581647b..46c954b 100644 --- a/st.c +++ b/st.c @@ -461,7 +461,7 @@ selextend(int col, int row, int type, int done) { int oldey, oldex, oldsby, oldsey, oldtype; - if (!sel.mode) + if (sel.mode == SEL_IDLE) return; if (done && sel.mode == SEL_EMPTY) { selclear(); From a5a928bfc1dd049780a45e072cb4ee42de7219bf Mon Sep 17 00:00:00 2001 From: Hiltjo Posthuma Date: Tue, 20 Mar 2018 21:22:27 +0100 Subject: [PATCH 070/129] don't modify argv, use a counter on some platforms (OpenBSD) this changes the exposed argv in tools using the kvm_* interface, such as ps and pgrep. --- arg.h | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) 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 From f4020b2cc4fe45c9e8bfe47fc73deccd867cf9de Mon Sep 17 00:00:00 2001 From: Hiltjo Posthuma Date: Tue, 20 Mar 2018 21:25:30 +0100 Subject: [PATCH 071/129] fix regression by selecting clipboard text "restore the old behaviour that the primary doesn't get deleted by a simple left click" Patch by Daniel Tameling , thanks! --- x.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/x.c b/x.c index 12bc86b..c343ba2 100644 --- a/x.c +++ b/x.c @@ -618,6 +618,9 @@ selrequest(XEvent *e) void setsel(char *str, Time t) { + if (!str) + return; + free(xsel.primary); xsel.primary = str; From 6f0f2b7ec3713351de274707672fbadb6cc727a2 Mon Sep 17 00:00:00 2001 From: Hiltjo Posthuma Date: Tue, 20 Mar 2018 21:29:10 +0100 Subject: [PATCH 072/129] bump version to 0.8.1 --- config.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config.mk b/config.mk index b2eac10..039c42c 100644 --- a/config.mk +++ b/config.mk @@ -1,5 +1,5 @@ # st version -VERSION = 0.8 +VERSION = 0.8.1 # Customize below to fit your system From 74cff67bd7746c2636ea7bc78a0b8af2f8c44838 Mon Sep 17 00:00:00 2001 From: Daniel Tameling Date: Wed, 28 Mar 2018 21:27:58 +0200 Subject: [PATCH 073/129] set sel.alt in selstart instead of selextend --- st.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/st.c b/st.c index 46c954b..2612c95 100644 --- a/st.c +++ b/st.c @@ -446,6 +446,7 @@ selstart(int col, int row, int snap) selclear(); sel.mode = SEL_EMPTY; sel.type = SEL_REGULAR; + sel.alt = IS_SET(MODE_ALTSCREEN); sel.snap = snap; sel.oe.x = sel.ob.x = col; sel.oe.y = sel.ob.y = row; @@ -474,7 +475,6 @@ selextend(int col, int row, int type, int done) oldsey = sel.ne.y; oldtype = sel.type; - sel.alt = IS_SET(MODE_ALTSCREEN); sel.oe.x = col; sel.oe.y = row; selnormalize(); From bd3f7fd84270025696790512cf3c2dafaf5bc77f Mon Sep 17 00:00:00 2001 From: Hiltjo Posthuma Date: Thu, 29 Mar 2018 18:18:30 +0200 Subject: [PATCH 074/129] st -v: remove years and copyright text --- x.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x.c b/x.c index c343ba2..f0195c9 100644 --- a/x.c +++ b/x.c @@ -1925,7 +1925,7 @@ main(int argc, char *argv[]) opt_embed = EARGF(usage()); break; case 'v': - die("%s " VERSION " (c) 2010-2016 st engineers\n", argv0); + die("%s " VERSION "\n", argv0); break; default: usage(); From 041912a791e8c2f4d5d2415b16210d29d7e701c5 Mon Sep 17 00:00:00 2001 From: Hiltjo Posthuma Date: Thu, 29 Mar 2018 18:30:05 +0200 Subject: [PATCH 075/129] error message style and use strerror in a few places --- st.c | 21 +++++++++++---------- x.c | 27 +++++++++++++-------------- 2 files changed, 24 insertions(+), 24 deletions(-) diff --git a/st.c b/st.c index 2612c95..0628707 100644 --- a/st.c +++ b/st.c @@ -256,10 +256,10 @@ xwrite(int fd, const char *s, size_t len) void * xmalloc(size_t len) { - void *p = malloc(len); + void *p; - if (!p) - die("Out of memory\n"); + if (!(p = malloc(len))) + die("malloc: %s\n", strerror(errno)); return p; } @@ -268,7 +268,7 @@ void * xrealloc(void *p, size_t len) { if ((p = realloc(p, len)) == NULL) - die("Out of memory\n"); + die("realloc: %s\n", strerror(errno)); return p; } @@ -277,7 +277,7 @@ char * xstrdup(char *s) { if ((s = strdup(s)) == NULL) - die("Out of memory\n"); + die("strdup: %s\n", strerror(errno)); return s; } @@ -687,7 +687,7 @@ execsh(char *cmd, char **args) errno = 0; if ((pw = getpwuid(getuid())) == NULL) { if (errno) - die("getpwuid:%s\n", strerror(errno)); + die("getpwuid: %s\n", strerror(errno)); else die("who are you?\n"); } @@ -730,7 +730,7 @@ sigchld(int a) pid_t p; if ((p = waitpid(pid, &stat, WNOHANG)) < 0) - die("Waiting for pid %hd failed: %s\n", pid, strerror(errno)); + die("waiting for pid %hd failed: %s\n", pid, strerror(errno)); if (pid != p) return; @@ -781,7 +781,8 @@ ttynew(char *line, char *cmd, char *out, char **args) if (line) { if ((cmdfd = open(line, O_RDWR)) < 0) - die("open line failed: %s\n", strerror(errno)); + die("open line '%s' failed: %s\n", + line, strerror(errno)); dup2(cmdfd, 0); stty(args); return cmdfd; @@ -793,7 +794,7 @@ ttynew(char *line, char *cmd, char *out, char **args) switch (pid = fork()) { case -1: - die("fork failed\n"); + die("fork failed: %s\n", strerror(errno)); break; case 0: close(iofd); @@ -826,7 +827,7 @@ ttyread(void) /* 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)); + die("couldn't read from shell: %s\n", strerror(errno)); buflen += ret; written = twrite(buf, buflen, 0); diff --git a/x.c b/x.c index f0195c9..c0bd890 100644 --- a/x.c +++ b/x.c @@ -742,9 +742,9 @@ xloadcols(void) 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]); + die("could not allocate color '%s'\n", colorname[i]); else - die("Could not allocate color %d\n", i); + die("could not allocate color %d\n", i); } loaded = 1; } @@ -869,7 +869,7 @@ xloadfont(Font *f, FcPattern *pattern) if ((XftPatternGetInteger(f->match->pattern, "slant", 0, &haveattr) != XftResultMatch) || haveattr < wantattr) { f->badslant = 1; - fputs("st: font slant does not match\n", stderr); + fputs("font slant does not match\n", stderr); } } @@ -878,7 +878,7 @@ xloadfont(Font *f, FcPattern *pattern) if ((XftPatternGetInteger(f->match->pattern, "weight", 0, &haveattr) != XftResultMatch) || haveattr != wantattr) { f->badweight = 1; - fputs("st: font weight does not match\n", stderr); + fputs("font weight does not match\n", stderr); } } @@ -906,14 +906,13 @@ xloadfonts(char *fontstr, double fontsize) FcPattern *pattern; double fontval; - if (fontstr[0] == '-') { + if (fontstr[0] == '-') pattern = XftXlfdParse(fontstr, False, False); - } else { + else pattern = FcNameParse((FcChar8 *)fontstr); - } if (!pattern) - die("st: can't open font %s\n", fontstr); + die("can't open font %s\n", fontstr); if (fontsize > 1) { FcPatternDel(pattern, FC_PIXEL_SIZE); @@ -939,7 +938,7 @@ xloadfonts(char *fontstr, double fontsize) } if (xloadfont(&dc.font, pattern)) - die("st: can't open font %s\n", fontstr); + die("can't open font %s\n", fontstr); if (usedfontsize < 0) { FcPatternGetDouble(dc.font.match->pattern, @@ -956,17 +955,17 @@ xloadfonts(char *fontstr, double fontsize) 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); + die("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); + die("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); + die("can't open font %s\n", fontstr); FcPatternDestroy(pattern); } @@ -1003,13 +1002,13 @@ xinit(int cols, int rows) XColor xmousefg, xmousebg; if (!(xw.dpy = XOpenDisplay(NULL))) - die("Can't open display\n"); + die("can't open display\n"); xw.scr = XDefaultScreen(xw.dpy); xw.vis = XDefaultVisual(xw.dpy, xw.scr); /* font */ if (!FcInit()) - die("Could not init fontconfig.\n"); + die("could not init fontconfig.\n"); usedfont = (opt_font == NULL)? font : opt_font; xloadfonts(usedfont, 0); From 30ce2cc002585409b36c630512c6ca4db8f88f15 Mon Sep 17 00:00:00 2001 From: Hiltjo Posthuma Date: Fri, 25 May 2018 11:59:28 +0200 Subject: [PATCH 076/129] Pledge on OpenBSD --- config.mk | 6 ++++++ st.c | 8 ++++++++ 2 files changed, 14 insertions(+) diff --git a/config.mk b/config.mk index 039c42c..c7355f1 100644 --- a/config.mk +++ b/config.mk @@ -23,6 +23,12 @@ CPPFLAGS = -DVERSION=\"$(VERSION)\" -D_XOPEN_SOURCE=600 STCFLAGS = $(INCS) $(CPPFLAGS) $(CFLAGS) STLDFLAGS = $(LIBS) $(LDFLAGS) +# OpenBSD: +#CPPFLAGS = -DVERSION=\"$(VERSION)\" -D_XOPEN_SOURCE=600 -D_BSD_SOURCE +#LIBS = -L$(X11LIB) -lm -lX11 -lutil -lXft \ +# `pkg-config --libs fontconfig` \ +# `pkg-config --libs freetype2` + # compiler and linker # CC = c99 diff --git a/st.c b/st.c index 0628707..b9750f2 100644 --- a/st.c +++ b/st.c @@ -28,6 +28,10 @@ #include #endif +#ifndef __OpenBSD__ +#define pledge(a,b) 0 +#endif + /* Arbitrary sizes */ #define UTF_INVALID 0xFFFD #define UTF_SIZ 4 @@ -806,9 +810,13 @@ ttynew(char *line, char *cmd, char *out, char **args) die("ioctl TIOCSCTTY failed: %s\n", strerror(errno)); close(s); close(m); + if (pledge("stdio getpw proc exec", NULL) == -1) + die("pledge\n"); execsh(cmd, args); break; default: + if (pledge("stdio rpath tty proc", NULL) == -1) + die("pledge\n"); close(s); cmdfd = m; signal(SIGCHLD, sigchld); From 235a783e039986fca3ccefec08ea45804dab196f Mon Sep 17 00:00:00 2001 From: Hiltjo Posthuma Date: Fri, 25 May 2018 13:04:09 +0200 Subject: [PATCH 077/129] code-style for pledge(2) feedback from Klemens, thanks --- st.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/st.c b/st.c index b9750f2..76bb3ea 100644 --- a/st.c +++ b/st.c @@ -28,10 +28,6 @@ #include #endif -#ifndef __OpenBSD__ -#define pledge(a,b) 0 -#endif - /* Arbitrary sizes */ #define UTF_INVALID 0xFFFD #define UTF_SIZ 4 @@ -810,13 +806,17 @@ ttynew(char *line, char *cmd, char *out, char **args) die("ioctl TIOCSCTTY failed: %s\n", strerror(errno)); close(s); close(m); +#ifdef __OpenBSD__ if (pledge("stdio getpw proc exec", NULL) == -1) die("pledge\n"); +#endif execsh(cmd, args); break; default: +#ifdef __OpenBSD__ if (pledge("stdio rpath tty proc", NULL) == -1) die("pledge\n"); +#endif close(s); cmdfd = m; signal(SIGCHLD, sigchld); From dc3b5babf1f8639a0d65cd347fc7879ac0461012 Mon Sep 17 00:00:00 2001 From: Hiltjo Posthuma Date: Sat, 2 Jun 2018 17:11:14 +0200 Subject: [PATCH 078/129] config.mk: remove extra newline before EOF --- config.mk | 1 - 1 file changed, 1 deletion(-) diff --git a/config.mk b/config.mk index c7355f1..e676105 100644 --- a/config.mk +++ b/config.mk @@ -31,4 +31,3 @@ STLDFLAGS = $(LIBS) $(LDFLAGS) # compiler and linker # CC = c99 - From 29f341da7cf32888f45005e08de202d9a372d972 Mon Sep 17 00:00:00 2001 From: Jules Maselbas Date: Wed, 27 Jun 2018 17:08:30 +0200 Subject: [PATCH 079/129] Fix crash on resize Prevent to realloc xw.specbuc with a negative number of col. Add proper hints for the minimal size, for one character. --- x.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/x.c b/x.c index c0bd890..00cb6b1 100644 --- a/x.c +++ b/x.c @@ -672,6 +672,8 @@ cresize(int width, int height) col = (win.w - 2 * borderpx) / win.cw; row = (win.h - 2 * borderpx) / win.ch; + col = MAX(1, col); + row = MAX(1, row); tresize(col, row); xresize(col, row); @@ -681,8 +683,8 @@ cresize(int width, int height) void xresize(int col, int row) { - win.tw = MAX(1, col * win.cw); - win.th = MAX(1, row * win.ch); + win.tw = col * win.cw; + win.th = row * win.ch; XFreePixmap(xw.dpy, xw.buf); xw.buf = XCreatePixmap(xw.dpy, xw.win, win.w, win.h, @@ -788,15 +790,17 @@ xhints(void) sizeh = XAllocSizeHints(); - sizeh->flags = PSize | PResizeInc | PBaseSize; + sizeh->flags = PSize | PResizeInc | PBaseSize | PMinSize; 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; + sizeh->min_height = win.ch + 2 * borderpx; + sizeh->min_width = win.cw + 2 * borderpx; if (xw.isfixed) { - sizeh->flags |= PMaxSize | PMinSize; + sizeh->flags |= PMaxSize; sizeh->min_width = sizeh->max_width = win.w; sizeh->min_height = sizeh->max_height = win.h; } From 1911c9274d9b03f3d7999c6ce26e2d5169642d26 Mon Sep 17 00:00:00 2001 From: Jules Maselbas Date: Sat, 14 Jul 2018 11:16:36 +0200 Subject: [PATCH 080/129] Simplify cursor color handling --- x.c | 30 ++++++++++++------------------ 1 file changed, 12 insertions(+), 18 deletions(-) diff --git a/x.c b/x.c index 00cb6b1..ffd005f 100644 --- a/x.c +++ b/x.c @@ -1418,25 +1418,19 @@ xdrawcursor(int cx, int cy, Glyph g, int ox, int oy, Glyph og) */ 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; - } + if (selected(cx, cy)) { + g.bg = defaultrcs; + g.fg = defaultfg; } else { - if (selected(cx, cy)) { - g.fg = defaultfg; - g.bg = defaultrcs; - } else { - g.fg = defaultbg; - g.bg = defaultcs; - } - drawcol = dc.col[g.bg]; + g.bg = defaultcs; + g.fg = defaultbg; + } + drawcol = dc.col[g.bg]; + + if (IS_SET(MODE_REVERSE)) { + drawcol.color.red = ~drawcol.color.red; + drawcol.color.green = ~drawcol.color.green; + drawcol.color.blue = ~drawcol.color.blue; } /* draw the new one */ From b51bcd5553af3db394014efbd78acf7828fa48ff Mon Sep 17 00:00:00 2001 From: Jules Maselbas Date: Sat, 14 Jul 2018 11:16:37 +0200 Subject: [PATCH 081/129] Make cursor follow text color --- config.def.h | 2 -- x.c | 12 +++++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/config.def.h b/config.def.h index 82b1b09..ca6b0db 100644 --- a/config.def.h +++ b/config.def.h @@ -118,8 +118,6 @@ static const char *colorname[] = { */ unsigned int defaultfg = 7; unsigned int defaultbg = 0; -static unsigned int defaultcs = 256; -static unsigned int defaultrcs = 257; /* * Default shape of cursor diff --git a/x.c b/x.c index ffd005f..b51821d 100644 --- a/x.c +++ b/x.c @@ -1419,13 +1419,15 @@ xdrawcursor(int cx, int cy, Glyph g, int ox, int oy, Glyph og) g.mode &= ATTR_BOLD|ATTR_ITALIC|ATTR_UNDERLINE|ATTR_STRUCK|ATTR_WIDE; if (selected(cx, cy)) { - g.bg = defaultrcs; - g.fg = defaultfg; + drawcol = dc.col[g.bg]; } else { - g.bg = defaultcs; - g.fg = defaultbg; + g.mode |= ATTR_REVERSE; + + if (g.mode & ATTR_BOLD && BETWEEN(g.fg, 0, 7)) + drawcol = dc.col[g.fg + 8]; + else + drawcol = dc.col[g.fg]; } - drawcol = dc.col[g.bg]; if (IS_SET(MODE_REVERSE)) { drawcol.color.red = ~drawcol.color.red; From 5535c1f04c665c05faff2a65d5558246b7748d49 Mon Sep 17 00:00:00 2001 From: Jules Maselbas Date: Sun, 15 Jul 2018 13:53:37 +0200 Subject: [PATCH 082/129] Fix crash when cursor color is truecolor Reported-by: Ivan Tham --- x.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/x.c b/x.c index b51821d..4155a70 100644 --- a/x.c +++ b/x.c @@ -1404,6 +1404,7 @@ void xdrawcursor(int cx, int cy, Glyph g, int ox, int oy, Glyph og) { Color drawcol; + uint32_t cc; /* remove the old cursor */ if (selected(ox, oy)) @@ -1419,14 +1420,22 @@ xdrawcursor(int cx, int cy, Glyph g, int ox, int oy, Glyph og) g.mode &= ATTR_BOLD|ATTR_ITALIC|ATTR_UNDERLINE|ATTR_STRUCK|ATTR_WIDE; if (selected(cx, cy)) { - drawcol = dc.col[g.bg]; + cc = g.bg; } else { g.mode |= ATTR_REVERSE; - if (g.mode & ATTR_BOLD && BETWEEN(g.fg, 0, 7)) - drawcol = dc.col[g.fg + 8]; + cc = g.fg + 8; else - drawcol = dc.col[g.fg]; + cc = g.fg; + } + + if (IS_TRUECOL(cc)) { + drawcol.color.alpha = 0xffff; + drawcol.color.red = TRUERED(cc); + drawcol.color.green = TRUEGREEN(cc); + drawcol.color.blue = TRUEBLUE(cc); + } else { + drawcol = dc.col[cc]; } if (IS_SET(MODE_REVERSE)) { From 732be223ee7ba5486713c63f944699fd6285af96 Mon Sep 17 00:00:00 2001 From: Hiltjo Posthuma Date: Tue, 17 Jul 2018 20:01:54 +0200 Subject: [PATCH 083/129] Revert "Fix crash when cursor color is truecolor" This reverts commit 5535c1f04c665c05faff2a65d5558246b7748d49. --- x.c | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/x.c b/x.c index 4155a70..b51821d 100644 --- a/x.c +++ b/x.c @@ -1404,7 +1404,6 @@ void xdrawcursor(int cx, int cy, Glyph g, int ox, int oy, Glyph og) { Color drawcol; - uint32_t cc; /* remove the old cursor */ if (selected(ox, oy)) @@ -1420,22 +1419,14 @@ xdrawcursor(int cx, int cy, Glyph g, int ox, int oy, Glyph og) g.mode &= ATTR_BOLD|ATTR_ITALIC|ATTR_UNDERLINE|ATTR_STRUCK|ATTR_WIDE; if (selected(cx, cy)) { - cc = g.bg; + drawcol = dc.col[g.bg]; } else { g.mode |= ATTR_REVERSE; + if (g.mode & ATTR_BOLD && BETWEEN(g.fg, 0, 7)) - cc = g.fg + 8; + drawcol = dc.col[g.fg + 8]; else - cc = g.fg; - } - - if (IS_TRUECOL(cc)) { - drawcol.color.alpha = 0xffff; - drawcol.color.red = TRUERED(cc); - drawcol.color.green = TRUEGREEN(cc); - drawcol.color.blue = TRUEBLUE(cc); - } else { - drawcol = dc.col[cc]; + drawcol = dc.col[g.fg]; } if (IS_SET(MODE_REVERSE)) { From 8ed7a4b3b755407a7724a586ef224051bc306f4f Mon Sep 17 00:00:00 2001 From: Hiltjo Posthuma Date: Tue, 17 Jul 2018 20:01:57 +0200 Subject: [PATCH 084/129] Revert "Make cursor follow text color" This reverts commit b51bcd5553af3db394014efbd78acf7828fa48ff. --- config.def.h | 2 ++ x.c | 12 +++++------- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/config.def.h b/config.def.h index ca6b0db..82b1b09 100644 --- a/config.def.h +++ b/config.def.h @@ -118,6 +118,8 @@ static const char *colorname[] = { */ unsigned int defaultfg = 7; unsigned int defaultbg = 0; +static unsigned int defaultcs = 256; +static unsigned int defaultrcs = 257; /* * Default shape of cursor diff --git a/x.c b/x.c index b51821d..ffd005f 100644 --- a/x.c +++ b/x.c @@ -1419,15 +1419,13 @@ xdrawcursor(int cx, int cy, Glyph g, int ox, int oy, Glyph og) g.mode &= ATTR_BOLD|ATTR_ITALIC|ATTR_UNDERLINE|ATTR_STRUCK|ATTR_WIDE; if (selected(cx, cy)) { - drawcol = dc.col[g.bg]; + g.bg = defaultrcs; + g.fg = defaultfg; } else { - g.mode |= ATTR_REVERSE; - - if (g.mode & ATTR_BOLD && BETWEEN(g.fg, 0, 7)) - drawcol = dc.col[g.fg + 8]; - else - drawcol = dc.col[g.fg]; + g.bg = defaultcs; + g.fg = defaultbg; } + drawcol = dc.col[g.bg]; if (IS_SET(MODE_REVERSE)) { drawcol.color.red = ~drawcol.color.red; From 4f4bccd1627c845330235721f593d2e93418723d Mon Sep 17 00:00:00 2001 From: Hiltjo Posthuma Date: Tue, 17 Jul 2018 20:01:58 +0200 Subject: [PATCH 085/129] Revert "Simplify cursor color handling" This reverts commit 1911c9274d9b03f3d7999c6ce26e2d5169642d26. --- x.c | 30 ++++++++++++++++++------------ 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/x.c b/x.c index ffd005f..00cb6b1 100644 --- a/x.c +++ b/x.c @@ -1418,19 +1418,25 @@ xdrawcursor(int cx, int cy, Glyph g, int ox, int oy, Glyph og) */ g.mode &= ATTR_BOLD|ATTR_ITALIC|ATTR_UNDERLINE|ATTR_STRUCK|ATTR_WIDE; - if (selected(cx, cy)) { - g.bg = defaultrcs; - g.fg = defaultfg; - } else { - g.bg = defaultcs; - g.fg = defaultbg; - } - drawcol = dc.col[g.bg]; - if (IS_SET(MODE_REVERSE)) { - drawcol.color.red = ~drawcol.color.red; - drawcol.color.green = ~drawcol.color.green; - drawcol.color.blue = ~drawcol.color.blue; + 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 */ From 67d0cb65d0794e2d91e72e5fa1e3612172e5812e Mon Sep 17 00:00:00 2001 From: Quentin Rameau Date: Tue, 11 Sep 2018 13:11:28 +0200 Subject: [PATCH 086/129] Remove the ISO 14755 feature And move it to the patches section. Keeping it would force to add an exec pledge on OpenBSD, and some people think it's bloated, so bye! --- config.def.h | 1 - st.1 | 4 ---- st.c | 26 -------------------------- st.h | 1 - 4 files changed, 32 deletions(-) diff --git a/config.def.h b/config.def.h index 82b1b09..823e79f 100644 --- a/config.def.h +++ b/config.def.h @@ -177,7 +177,6 @@ static Shortcut shortcuts[] = { { 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} }, }; /* diff --git a/st.1 b/st.1 index 81bceff..e8d6059 100644 --- a/st.1 +++ b/st.1 @@ -159,10 +159,6 @@ Copy the selected text to the clipboard selection. .TP .B Ctrl-Shift-v Paste from the clipboard selection. -.TP -.B Ctrl-Shift-i -Launch dmenu to enter a unicode codepoint and send the corresponding glyph -to st. .SH CUSTOMIZATION .B st can be customized by creating a custom config.h and (re)compiling the source diff --git a/st.c b/st.c index 76bb3ea..574dbee 100644 --- a/st.c +++ b/st.c @@ -38,15 +38,11 @@ /* macros */ #define IS_SET(flag) ((term.mode & (flag)) != 0) -#define NUMMAXLEN(x) ((int)(sizeof(x) * 2.56 + 0.5) + 1) #define ISCONTROLC0(c) (BETWEEN(c, 0, 0x1f) || (c) == '\177') #define ISCONTROLC1(c) (BETWEEN(c, 0x80, 0x9f)) #define ISCONTROL(c) (ISCONTROLC0(c) || ISCONTROLC1(c)) #define ISDELIM(u) (utf8strchr(worddelimiters, u) != NULL) -/* constants */ -#define ISO14755CMD "dmenu -w \"$WINDOWID\" -p codepoint: 7) - return; - if ((utf32 = strtoul(us, &e, 16)) == ULONG_MAX || - (*e != '\n' && *e != '\0')) - return; - - ttywrite(uc, utf8encode(utf32, uc), 1); -} - void toggleprinter(const Arg *arg) { diff --git a/st.h b/st.h index dac64d8..38c61c4 100644 --- a/st.h +++ b/st.h @@ -80,7 +80,6 @@ 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 *); From 30ec9a3dc354ab1a561c9edd808046bdf5dfd392 Mon Sep 17 00:00:00 2001 From: Hiltjo Posthuma Date: Tue, 11 Sep 2018 19:06:35 +0200 Subject: [PATCH 087/129] small code-style fix --- st.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/st.c b/st.c index 574dbee..46cf2da 100644 --- a/st.c +++ b/st.c @@ -1452,7 +1452,8 @@ tsetattr(int *attr, int l) } else { fprintf(stderr, "erresc(default): gfx attr %d unknown\n", - attr[i]), csidump(); + attr[i]); + csidump(); } break; } From b4d68d4daa2716c0064605a2a92082a7287ee54a Mon Sep 17 00:00:00 2001 From: Hiltjo Posthuma Date: Sun, 4 Nov 2018 14:30:56 +0100 Subject: [PATCH 088/129] st: small typofix in comment --- st.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/st.c b/st.c index 46cf2da..a51d19c 100644 --- a/st.c +++ b/st.c @@ -2262,7 +2262,7 @@ eschandle(uchar ascii) case 'Z': /* DECID -- Identify Terminal */ ttywrite(vtiden, strlen(vtiden), 0); break; - case 'c': /* RIS -- Reset to inital state */ + case 'c': /* RIS -- Reset to initial state */ treset(); resettitle(); xloadcols(); From d7bf023b2f2d41cb6983bb3ce2c6d1bf049150b3 Mon Sep 17 00:00:00 2001 From: Hiltjo Posthuma Date: Sun, 4 Nov 2018 14:35:07 +0100 Subject: [PATCH 089/129] fix memory leak in xloadcols() reported by Avi Halachmi (:avih)" patch slightly changed by me. --- x.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/x.c b/x.c index 00cb6b1..0422421 100644 --- a/x.c +++ b/x.c @@ -733,12 +733,12 @@ xloadcols(void) 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); + } else { + dc.collen = MAX(LEN(colorname), 256); + dc.col = xmalloc(dc.collen * sizeof(Color)); } for (i = 0; i < dc.collen; i++) From 096b125db7ec254002a049ef3a5c1204bd7f0ad9 Mon Sep 17 00:00:00 2001 From: Lauri Tirkkonen Date: Tue, 11 Dec 2018 11:43:03 +0200 Subject: [PATCH 090/129] output child WEXITSTATUS/WTERMSIG on abnormal termination --- st.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/st.c b/st.c index a51d19c..b8e6077 100644 --- a/st.c +++ b/st.c @@ -731,8 +731,10 @@ sigchld(int a) if (pid != p) return; - if (!WIFEXITED(stat) || WEXITSTATUS(stat)) - die("child finished with error '%d'\n", stat); + if (WIFEXITED(stat) && WEXITSTATUS(stat)) + die("child exited with status %d\n", WEXITSTATUS(stat)); + else if (WIFSIGNALED(stat)) + die("child terminated due to signal %d\n", WTERMSIG(stat)); exit(0); } From 7e19e116764d2651721cb9062ccaac31b0c771f2 Mon Sep 17 00:00:00 2001 From: Hiltjo Posthuma Date: Fri, 4 Jan 2019 12:33:01 +0100 Subject: [PATCH 091/129] Makefile: fix dependencies on config.h patch by Younes Khoudli (changed slightly). Thanks --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 0b3cecd..470ac86 100644 --- a/Makefile +++ b/Makefile @@ -22,7 +22,7 @@ config.h: $(CC) $(STCFLAGS) -c $< st.o: config.h st.h win.h -x.o: arg.h st.h win.h +x.o: arg.h config.h st.h win.h $(OBJ): config.h config.mk From e23acb9188b7bc7a7cfc418ac45671003abcc341 Mon Sep 17 00:00:00 2001 From: Paride Legovini Date: Fri, 4 Jan 2019 09:48:37 +0100 Subject: [PATCH 092/129] Set the path of pkg-config in a variable instead of hardcoding it In this way the path of pkg-config can be overridden from the command line. This is useful for example when cross-compiling. --- config.mk | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/config.mk b/config.mk index e676105..64a1da9 100644 --- a/config.mk +++ b/config.mk @@ -10,13 +10,15 @@ MANPREFIX = $(PREFIX)/share/man X11INC = /usr/X11R6/include X11LIB = /usr/X11R6/lib +PKG_CONFIG = pkg-config + # includes and libs INCS = -I$(X11INC) \ - `pkg-config --cflags fontconfig` \ - `pkg-config --cflags freetype2` + `$(PKG_CONFIG) --cflags fontconfig` \ + `$(PKG_CONFIG) --cflags freetype2` LIBS = -L$(X11LIB) -lm -lrt -lX11 -lutil -lXft \ - `pkg-config --libs fontconfig` \ - `pkg-config --libs freetype2` + `$(PKG_CONFIG) --libs fontconfig` \ + `$(PKG_CONFIG) --libs freetype2` # flags CPPFLAGS = -DVERSION=\"$(VERSION)\" -D_XOPEN_SOURCE=600 From 16d98738e74f189b3a00c23390ab5a9a22b056a1 Mon Sep 17 00:00:00 2001 From: Paride Legovini Date: Thu, 10 Jan 2019 13:36:09 +0100 Subject: [PATCH 093/129] Let the user specify CPPFLAGS This complements the work done in d4928ed, allowing the user to specify the preprocessor flags with the CPPFLAGS environment variable. This is useful for example to specify preprocessor macros with -D. CFLAGS could be used instead, but CPPFLAGS is more correct and is expected to be honored in some cases. For example, the helper scripts to build Debian packages make use of CPPFLAGS, but the variable is currently being ignored unless manually appended to CFLAGS. --- config.mk | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/config.mk b/config.mk index 64a1da9..5059632 100644 --- a/config.mk +++ b/config.mk @@ -21,8 +21,8 @@ LIBS = -L$(X11LIB) -lm -lrt -lX11 -lutil -lXft \ `$(PKG_CONFIG) --libs freetype2` # flags -CPPFLAGS = -DVERSION=\"$(VERSION)\" -D_XOPEN_SOURCE=600 -STCFLAGS = $(INCS) $(CPPFLAGS) $(CFLAGS) +STCPPFLAGS = -DVERSION=\"$(VERSION)\" -D_XOPEN_SOURCE=600 +STCFLAGS = $(INCS) $(STCPPFLAGS) $(CPPFLAGS) $(CFLAGS) STLDFLAGS = $(LIBS) $(LDFLAGS) # OpenBSD: From 3be4cf11d79ca87ff1fbbb57801913ec6f822429 Mon Sep 17 00:00:00 2001 From: Hiltjo Posthuma Date: Thu, 10 Jan 2019 18:16:17 +0100 Subject: [PATCH 094/129] config: add Shift+Insert as selpaste() again This was changed before in: commit 20f713548de451b67db3306cf8cf7b2f38fee05c on Wed Jan 25 19:17:38 2017 --- config.def.h | 1 + 1 file changed, 1 insertion(+) diff --git a/config.def.h b/config.def.h index 823e79f..0e01717 100644 --- a/config.def.h +++ b/config.def.h @@ -176,6 +176,7 @@ static Shortcut shortcuts[] = { { 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} }, }; From 75f92eb3489275bfcad901e5ca424134eda6e2f4 Mon Sep 17 00:00:00 2001 From: Hiltjo Posthuma Date: Sat, 9 Feb 2019 12:48:39 +0100 Subject: [PATCH 095/129] bump version to 0.8.2 --- config.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config.mk b/config.mk index 5059632..0cbb002 100644 --- a/config.mk +++ b/config.mk @@ -1,5 +1,5 @@ # st version -VERSION = 0.8.1 +VERSION = 0.8.2 # Customize below to fit your system From e85b6b64660214121164ea97fb098eaa4935f7db Mon Sep 17 00:00:00 2001 From: Ivan Tham Date: Tue, 12 Feb 2019 18:41:41 +0100 Subject: [PATCH 096/129] better Input Method Editor (IME) support Features: - Allow input methods swap with hotkey (E.g. left ctrl + left shift). - Over-the-spot pre-editing style, pre-edit data placed over insertion point. - Restart IME without segmentation fault. TODO: - Automatically pickup IME if st started before IME --- st.c | 1 + win.h | 1 + x.c | 69 ++++++++++++++++++++++++++++++++++++++++++++--------------- 3 files changed, 54 insertions(+), 17 deletions(-) diff --git a/st.c b/st.c index b8e6077..cf8687e 100644 --- a/st.c +++ b/st.c @@ -2594,6 +2594,7 @@ draw(void) term.ocx, term.ocy, term.line[term.ocy][term.ocx]); term.ocx = cx, term.ocy = term.c.y; xfinishdraw(); + xximspot(term.ocx, term.ocy); } void diff --git a/win.h b/win.h index 31f327d..a6ef1b9 100644 --- a/win.h +++ b/win.h @@ -36,3 +36,4 @@ void xsetmode(int, unsigned int); void xsetpointermotion(int); void xsetsel(char *); int xstartdraw(void); +void xximspot(int, int); diff --git a/x.c b/x.c index 0422421..865dacc 100644 --- a/x.c +++ b/x.c @@ -139,6 +139,9 @@ 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 ximopen(Display *); +static void ximinstantiate(Display *, XPointer, XPointer); +static void ximdestroy(XIM, XPointer, XPointer); static void xinit(int, int); static void cresize(int, int); static void xresize(int, int); @@ -996,6 +999,43 @@ xunloadfonts(void) xunloadfont(&dc.ibfont); } +void +ximopen(Display *dpy) +{ + XIMCallback destroy = { .client_data = NULL, .callback = ximdestroy }; + + if ((xw.xim = XOpenIM(xw.dpy, NULL, NULL, NULL)) == NULL) { + XSetLocaleModifiers("@im=local"); + if ((xw.xim = XOpenIM(xw.dpy, NULL, NULL, NULL)) == NULL) { + XSetLocaleModifiers("@im="); + if ((xw.xim = XOpenIM(xw.dpy, NULL, NULL, NULL)) == NULL) + die("XOpenIM failed. Could not open input device.\n"); + } + } + if (XSetIMValues(xw.xim, XNDestroyCallback, &destroy, NULL) != NULL) + die("XSetIMValues failed. Could not set input method value.\n"); + xw.xic = XCreateIC(xw.xim, XNInputStyle, XIMPreeditNothing | XIMStatusNothing, + XNClientWindow, xw.win, XNFocusWindow, xw.win, NULL); + if (xw.xic == NULL) + die("XCreateIC failed. Could not obtain input method.\n"); +} + +void +ximinstantiate(Display *dpy, XPointer client, XPointer call) +{ + ximopen(dpy); + XUnregisterIMInstantiateCallback(xw.dpy, NULL, NULL, NULL, + ximinstantiate, NULL); +} + +void +ximdestroy(XIM xim, XPointer client, XPointer call) +{ + xw.xim = NULL; + XRegisterIMInstantiateCallback(xw.dpy, NULL, NULL, NULL, + ximinstantiate, NULL); +} + void xinit(int cols, int rows) { @@ -1033,7 +1073,7 @@ xinit(int cols, int rows) 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 + xw.attrs.event_mask = FocusChangeMask | KeyPressMask | KeyReleaseMask | ExposureMask | VisibilityChangeMask | StructureNotifyMask | ButtonMotionMask | ButtonPressMask | ButtonReleaseMask; xw.attrs.colormap = xw.cmap; @@ -1061,22 +1101,7 @@ xinit(int cols, int rows) 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"); + ximopen(xw.dpy); /* white cursor, black outline */ cursor = XCreateFontCursor(xw.dpy, mouseshape); @@ -1554,6 +1579,16 @@ xfinishdraw(void) defaultfg : defaultbg].pixel); } +void +xximspot(int x, int y) +{ + XPoint spot = { borderpx + x * win.cw, borderpx + (y + 1) * win.ch }; + XVaNestedList attr = XVaCreateNestedList(0, XNSpotLocation, &spot, NULL); + + XSetICValues(xw.xic, XNPreeditAttributes, attr, NULL); + XFree(attr); +} + void expose(XEvent *ev) { From a8cb8e94547d7e31441d2444e8a196415e3e4c1f Mon Sep 17 00:00:00 2001 From: magras Date: Thu, 28 Feb 2019 04:56:01 +0300 Subject: [PATCH 097/129] fix use after free in font caching algorithm Current font caching algorithm contains a use after free error. A font removed from `frc` might be still listed in `wx.specbuf`. It will lead to a crash inside `XftDrawGlyphFontSpec()`. Steps to reproduce: $ st -f 'Misc Tamsyn:scalable=false' $ curl https://www.cl.cam.ac.uk/~mgk25/ucs/examples/UTF-8-demo.txt Of course, result depends on fonts installed on a system and fontconfig. In my case, I'm getting consistent segfaults with different fonts. I replaced a fixed array with a simple unbounded buffer with a constant growth rate. Cache starts with a capacity of 0, gets increments by 16, and never shrinks. On my machine after `cat UTF-8-demo.txt` buffer reaches a capacity of 192. During casual use capacity stays at 0. --- x.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/x.c b/x.c index 865dacc..2cd76d0 100644 --- a/x.c +++ b/x.c @@ -226,8 +226,9 @@ typedef struct { } Fontcache; /* Fontcache is an array now. A new font will be appended to the array. */ -static Fontcache frc[16]; +static Fontcache *frc = NULL; static int frclen = 0; +static int frccap = 0; static char *usedfont = NULL; static double usedfontsize = 0; static double defaultfontsize = 0; @@ -1244,12 +1245,14 @@ xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x fcpattern, &fcres); /* - * Overwrite or create the new cache entry. + * Allocate memory for the new cache entry. */ - if (frclen >= LEN(frc)) { - frclen = LEN(frc) - 1; - XftFontClose(xw.dpy, frc[frclen].font); - frc[frclen].unicodep = 0; + if (frclen >= frccap) { + frccap += 16; + if (!frc) + frc = xmalloc(frccap * sizeof(Fontcache)); + else + frc = xrealloc(frc, frccap * sizeof(Fontcache)); } frc[frclen].font = XftFontOpenPattern(xw.dpy, From 4e0135afeca43f5affe13d7269cb98e7ac526074 Mon Sep 17 00:00:00 2001 From: Hiltjo Posthuma Date: Sun, 3 Mar 2019 11:23:54 +0100 Subject: [PATCH 098/129] style: remove double empty newlines --- st.c | 1 - x.c | 2 -- 2 files changed, 3 deletions(-) diff --git a/st.c b/st.c index cf8687e..379dd10 100644 --- a/st.c +++ b/st.c @@ -2335,7 +2335,6 @@ tputc(Rune u) goto check_control_code; } - if (IS_SET(MODE_SIXEL)) { /* TODO: implement sixel mode */ return; diff --git a/x.c b/x.c index 2cd76d0..aa86b31 100644 --- a/x.c +++ b/x.c @@ -763,7 +763,6 @@ xsetcolorname(int x, const char *name) if (!BETWEEN(x, 0, dc.collen)) return 1; - if (!xloadcolor(x, name, &ncolor)) return 1; @@ -1769,7 +1768,6 @@ kpress(XEvent *ev) ttywrite(buf, len, 1); } - void cmessage(XEvent *e) { From ed68fe7dce2b21b4e0e595b99d47790e76812cb7 Mon Sep 17 00:00:00 2001 From: Hiltjo Posthuma Date: Sun, 3 Mar 2019 11:29:43 +0100 Subject: [PATCH 099/129] simplify (greedy) font caching allocating a bit POSIX says: "If ptr is a null pointer, realloc() shall be equivalent to malloc() for the specified size." --- x.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/x.c b/x.c index aa86b31..5828a3b 100644 --- a/x.c +++ b/x.c @@ -1243,15 +1243,10 @@ xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x fontpattern = FcFontSetMatch(0, fcsets, 1, fcpattern, &fcres); - /* - * Allocate memory for the new cache entry. - */ + /* Allocate memory for the new cache entry. */ if (frclen >= frccap) { frccap += 16; - if (!frc) - frc = xmalloc(frccap * sizeof(Fontcache)); - else - frc = xrealloc(frc, frccap * sizeof(Fontcache)); + frc = xrealloc(frc, frccap * sizeof(Fontcache)); } frc[frclen].font = XftFontOpenPattern(xw.dpy, From 75b4ba4b4be70a3ae429b1719d18b021839216d5 Mon Sep 17 00:00:00 2001 From: Lauri Tirkkonen Date: Wed, 13 Mar 2019 17:08:50 +0200 Subject: [PATCH 100/129] be silent about explicitly unhandled mouse modes --- st.c | 1 + 1 file changed, 1 insertion(+) diff --git a/st.c b/st.c index 379dd10..d35f89d 100644 --- a/st.c +++ b/st.c @@ -1575,6 +1575,7 @@ tsetmode(int priv, int set, int *args, int narg) case 1015: /* urxvt mangled mouse mode; incompatible and can be mistaken for other control codes. */ + break; default: fprintf(stderr, "erresc: unknown private set/reset mode %d\n", From d5efd256aa3840476579a27293ef1fb92a4b51e7 Mon Sep 17 00:00:00 2001 From: Lauri Tirkkonen Date: Wed, 13 Mar 2019 19:40:52 +0200 Subject: [PATCH 101/129] replace utf8strchr with wcschr --- config.def.h | 4 ++-- st.c | 20 +------------------- st.h | 2 +- 3 files changed, 4 insertions(+), 22 deletions(-) diff --git a/config.def.h b/config.def.h index 0e01717..482901e 100644 --- a/config.def.h +++ b/config.def.h @@ -30,9 +30,9 @@ static float chscale = 1.0; /* * word delimiter string * - * More advanced example: " `'\"()[]{}" + * More advanced example: L" `'\"()[]{}" */ -char *worddelimiters = " "; +wchar_t *worddelimiters = L" "; /* selection timeouts (in milliseconds) */ static unsigned int doubleclicktimeout = 300; diff --git a/st.c b/st.c index d35f89d..812f30c 100644 --- a/st.c +++ b/st.c @@ -41,7 +41,7 @@ #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 ISDELIM(u) (u != 0 && wcschr(worddelimiters, u) != NULL) enum term_mode { MODE_WRAP = 1 << 0, @@ -210,7 +210,6 @@ static void selsnap(int *, int *, int); static size_t utf8decode(const char *, Rune *, size_t); static Rune utf8decodebyte(char, size_t *); static char utf8encodebyte(Rune, size_t); -static char *utf8strchr(char *, Rune); static size_t utf8validate(Rune *, size_t); static char *base64dec(const char *); @@ -337,23 +336,6 @@ utf8encodebyte(Rune u, size_t i) return utfbyte[i] | (u & ~utfmask[i]); } -char * -utf8strchr(char *s, Rune u) -{ - Rune r; - size_t i, j, len; - - len = strlen(s); - for (i = 0, j = 0; i < len; i += j) { - if (!(j = utf8decode(&s[i], &r, len - i))) - break; - if (r == u) - return &(s[i]); - } - - return NULL; -} - size_t utf8validate(Rune *u, size_t i) { diff --git a/st.h b/st.h index 38c61c4..4da3051 100644 --- a/st.h +++ b/st.h @@ -114,7 +114,7 @@ char *xstrdup(char *); extern char *utmp; extern char *stty_args; extern char *vtiden; -extern char *worddelimiters; +extern wchar_t *worddelimiters; extern int allowaltscreen; extern char *termname; extern unsigned int tabspaces; From add0211522737b79dad990ccd65c8af63b5cc1dd Mon Sep 17 00:00:00 2001 From: Lauri Tirkkonen Date: Wed, 13 Mar 2019 17:15:04 +0200 Subject: [PATCH 102/129] use iswspace()/iswpunct() to find word delimiters this inverts the configuration logic: you no longer provide a list of delimiters -- all space and punctuation characters are considered delimiters, unless listed in extrawordchars. --- config.def.h | 7 ++++--- st.c | 3 ++- st.h | 2 +- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/config.def.h b/config.def.h index 482901e..9ce45a7 100644 --- a/config.def.h +++ b/config.def.h @@ -28,11 +28,12 @@ static float cwscale = 1.0; static float chscale = 1.0; /* - * word delimiter string + * all space and punctuation characters are considered word delimiters, unless + * listed here. * - * More advanced example: L" `'\"()[]{}" + * More advanced example: L"#$%&+,-./:=?_~" */ -wchar_t *worddelimiters = L" "; +wchar_t *extrawordchars = L"./:"; /* selection timeouts (in milliseconds) */ static unsigned int doubleclicktimeout = 300; diff --git a/st.c b/st.c index 812f30c..c383b43 100644 --- a/st.c +++ b/st.c @@ -16,6 +16,7 @@ #include #include #include +#include #include "st.h" #include "win.h" @@ -41,7 +42,7 @@ #define ISCONTROLC0(c) (BETWEEN(c, 0, 0x1f) || (c) == '\177') #define ISCONTROLC1(c) (BETWEEN(c, 0x80, 0x9f)) #define ISCONTROL(c) (ISCONTROLC0(c) || ISCONTROLC1(c)) -#define ISDELIM(u) (u != 0 && wcschr(worddelimiters, u) != NULL) +#define ISDELIM(u) ((iswspace(u) || iswpunct(u)) && wcschr(extrawordchars, u) == NULL) enum term_mode { MODE_WRAP = 1 << 0, diff --git a/st.h b/st.h index 4da3051..a3b19de 100644 --- a/st.h +++ b/st.h @@ -114,7 +114,7 @@ char *xstrdup(char *); extern char *utmp; extern char *stty_args; extern char *vtiden; -extern wchar_t *worddelimiters; +extern wchar_t *extrawordchars; extern int allowaltscreen; extern char *termname; extern unsigned int tabspaces; From 927621f6da015f51710c03279b00c6cc38057e32 Mon Sep 17 00:00:00 2001 From: Hiltjo Posthuma Date: Fri, 15 Mar 2019 12:31:54 +0100 Subject: [PATCH 103/129] config.def.h: tweak extra worddelimiters This changes the selection more like xterm. To test try: "find /" and select a path. --- config.def.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config.def.h b/config.def.h index 9ce45a7..ac5e8ce 100644 --- a/config.def.h +++ b/config.def.h @@ -33,7 +33,7 @@ static float chscale = 1.0; * * More advanced example: L"#$%&+,-./:=?_~" */ -wchar_t *extrawordchars = L"./:"; +wchar_t *extrawordchars = L""; /* selection timeouts (in milliseconds) */ static unsigned int doubleclicktimeout = 300; From 9acec468fbeaa9f90578352b610431ca9b2d4ee4 Mon Sep 17 00:00:00 2001 From: Hiltjo Posthuma Date: Fri, 15 Mar 2019 14:42:50 +0100 Subject: [PATCH 104/129] minor code-style, initialize var at the top of function --- st.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/st.c b/st.c index c383b43..f342e5c 100644 --- a/st.c +++ b/st.c @@ -1830,7 +1830,7 @@ csireset(void) void strhandle(void) { - char *p = NULL; + char *p = NULL, *dec; int j, narg, par; term.esc &= ~(ESC_STR_END|ESC_STR); @@ -1848,8 +1848,6 @@ strhandle(void) return; case 52: if (narg > 2) { - char *dec; - dec = base64dec(strescseq.args[2]); if (dec) { xsetsel(dec); From b650256044f867851725f712fdac58d4ff294808 Mon Sep 17 00:00:00 2001 From: Hiltjo Posthuma Date: Fri, 15 Mar 2019 14:44:28 +0100 Subject: [PATCH 105/129] dont print color warning on color reset OSC 104 without parameter also print explicitly "(null)" when printf "%s" p=NULL. noticed when exiting mutt: printf '\x1b]104\x07' --- st.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/st.c b/st.c index f342e5c..48d65ca 100644 --- a/st.c +++ b/st.c @@ -1865,7 +1865,10 @@ strhandle(void) case 104: /* color reset, here p = NULL */ j = (narg > 1) ? atoi(strescseq.args[1]) : -1; if (xsetcolorname(j, p)) { - fprintf(stderr, "erresc: invalid color %s\n", p); + if (par == 104 && narg <= 1) + return; /* color reset without parameter */ + fprintf(stderr, "erresc: invalid color j=%d, p=%s\n", + j, p ? p : "(null)"); } else { /* * TODO if defaultbg color is changed, borders From 21367a040f056f6a207fafa066bd1cb2d9cae586 Mon Sep 17 00:00:00 2001 From: Hiltjo Posthuma Date: Fri, 15 Mar 2019 20:40:16 +0100 Subject: [PATCH 106/129] revert part of commit add0211522737b79dad990ccd65c8af63b5cc1dd "use iswspace()/iswpunct() to find word delimiters this inverts the configuration logic: you no longer provide a list of delimiters -- all space and punctuation characters are considered delimiters, unless listed in extrawordchars." Feedback from IRC and personal preference. --- config.def.h | 7 +++---- st.c | 3 +-- st.h | 2 +- 3 files changed, 5 insertions(+), 7 deletions(-) diff --git a/config.def.h b/config.def.h index ac5e8ce..482901e 100644 --- a/config.def.h +++ b/config.def.h @@ -28,12 +28,11 @@ static float cwscale = 1.0; static float chscale = 1.0; /* - * all space and punctuation characters are considered word delimiters, unless - * listed here. + * word delimiter string * - * More advanced example: L"#$%&+,-./:=?_~" + * More advanced example: L" `'\"()[]{}" */ -wchar_t *extrawordchars = L""; +wchar_t *worddelimiters = L" "; /* selection timeouts (in milliseconds) */ static unsigned int doubleclicktimeout = 300; diff --git a/st.c b/st.c index 48d65ca..8e6ccb5 100644 --- a/st.c +++ b/st.c @@ -16,7 +16,6 @@ #include #include #include -#include #include "st.h" #include "win.h" @@ -42,7 +41,7 @@ #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) ((iswspace(u) || iswpunct(u)) && wcschr(extrawordchars, u) == NULL) +#define ISDELIM(u) (u && wcschr(worddelimiters, u)) enum term_mode { MODE_WRAP = 1 << 0, diff --git a/st.h b/st.h index a3b19de..4da3051 100644 --- a/st.h +++ b/st.h @@ -114,7 +114,7 @@ char *xstrdup(char *); extern char *utmp; extern char *stty_args; extern char *vtiden; -extern wchar_t *extrawordchars; +extern wchar_t *worddelimiters; extern int allowaltscreen; extern char *termname; extern unsigned int tabspaces; From f1546cf9c1f9fc52d26dbbcf73210901e83c7ecf Mon Sep 17 00:00:00 2001 From: "Avi Halachmi (:avih)" Date: Wed, 10 Apr 2019 01:54:43 +0300 Subject: [PATCH 107/129] selection: fix view to match actual selection on first cell --- st.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/st.c b/st.c index 8e6ccb5..ede7ae6 100644 --- a/st.c +++ b/st.c @@ -458,7 +458,7 @@ selextend(int col, int row, int type, int done) selnormalize(); sel.type = type; - if (oldey != sel.oe.y || oldex != sel.oe.x || oldtype != sel.type) + if (oldey != sel.oe.y || oldex != sel.oe.x || oldtype != sel.type || sel.mode == SEL_EMPTY) tsetdirt(MIN(sel.nb.y, oldsby), MAX(sel.ne.y, oldsey)); sel.mode = done ? SEL_IDLE : SEL_READY; From caa1d8fbea2b92bca24652af0fee874bdbbbb3e5 Mon Sep 17 00:00:00 2001 From: Hiltjo Posthuma Date: Fri, 17 May 2019 13:00:10 +0200 Subject: [PATCH 108/129] FAQ: add entry about color emoji Xft bug This has been asked many times on IRC and the mailinglist. Make it easier to find information about this particular Xft issue by adding it to the FAQ. --- FAQ | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/FAQ b/FAQ index 921c493..ecf7af8 100644 --- a/FAQ +++ b/FAQ @@ -165,3 +165,30 @@ Apply [1]. [1] http://st.suckless.org/patches/delkey +## BadLength X error in Xft when trying to render emoji + +Xft makes st crash when rendering color emojis with the following error: + +"X Error of failed request: BadLength (poly request too large or internal Xlib length error)" + Major opcode of failed request: 139 (RENDER) + Minor opcode of failed request: 20 (RenderAddGlyphs) + Serial number of failed request: 1595 + Current serial number in output stream: 1818" + +This is a known bug in Xft (not st) which happens on some platforms and +combination of particular fonts and fontconfig settings. + +See also: +https://gitlab.freedesktop.org/xorg/lib/libxft/issues/6 +https://bugs.freedesktop.org/show_bug.cgi?id=107534 +https://bugzilla.redhat.com/show_bug.cgi?id=1498269 + +The solution is to remove color emoji fonts or disable this in the fontconfig +XML configuration. As an ugly workaround (which may work only on newer +fontconfig versions (FC_COLOR)), the following code can be used to mask color +fonts: + + FcPatternAddBool(fcpattern, FC_COLOR, FcFalse); + +Please don't bother reporting this bug to st, but notify the upstream Xft +developers about fixing this bug. From 2b2344871cfb6143c15ae5f7c95a69c5f501f41c Mon Sep 17 00:00:00 2001 From: ethereal Date: Wed, 25 Jan 2017 14:10:56 -0800 Subject: [PATCH 109/129] Change from using xdg shell v5 to v6. Also fix shell return value detection. --- Makefile | 8 +++--- config.mk | 2 +- st.c | 82 +++++++++++++++++++++++++++++++++++-------------------- 3 files changed, 58 insertions(+), 34 deletions(-) diff --git a/Makefile b/Makefile index 053d3e0..af0a6c4 100644 --- a/Makefile +++ b/Makefile @@ -3,7 +3,7 @@ include config.mk -SRC = st.c xdg-shell-unstable-v5-protocol.c +SRC = st.c xdg-shell-unstable-v6-protocol.c OBJ = ${SRC:.c=.o} all: options st @@ -17,15 +17,15 @@ options: config.h: cp config.def.h config.h -xdg-shell-unstable-v5-protocol.c: +xdg-shell-unstable-v6-protocol.c: @echo GEN $@ @wayland-scanner code ${XDG_SHELL_PROTO} $@ -xdg-shell-unstable-v5-client-protocol.h: +xdg-shell-unstable-v6-client-protocol.h: @echo GEN $@ @wayland-scanner client-header ${XDG_SHELL_PROTO} $@ -st.o: xdg-shell-unstable-v5-client-protocol.h +st.o: xdg-shell-unstable-v6-client-protocol.h .c.o: @echo CC $< diff --git a/config.mk b/config.mk index 7da06f1..61377c8 100644 --- a/config.mk +++ b/config.mk @@ -8,7 +8,7 @@ PREFIX = /usr/local MANPREFIX = ${PREFIX}/share/man PKGCFG = fontconfig wayland-client wayland-cursor xkbcommon wld -XDG_SHELL_PROTO = `pkg-config --variable=pkgdatadir wayland-protocols`/unstable/xdg-shell/xdg-shell-unstable-v5.xml +XDG_SHELL_PROTO = `pkg-config --variable=pkgdatadir wayland-protocols`/unstable/xdg-shell/xdg-shell-unstable-v6.xml # includes and libs INCS = -I. -I/usr/include `pkg-config --cflags ${PKGCFG}` diff --git a/st.c b/st.c index d3bcfd8..d905620 100644 --- a/st.c +++ b/st.c @@ -33,7 +33,7 @@ #include #include "arg.h" -#include "xdg-shell-unstable-v5-client-protocol.h" +#include "xdg-shell-unstable-v6-client-protocol.h" char *argv0; @@ -276,8 +276,9 @@ typedef struct { struct wl_data_offer *seloffer; struct wl_surface *surface; struct wl_buffer *buffer; - struct xdg_shell *shell; - struct xdg_surface *xdgsurface; + struct zxdg_shell_v6 *shell; + struct zxdg_surface_v6 *xdgsurface; + struct zxdg_toplevel_v6 *xdgtoplevel; XKB xkb; bool configured; int px, py; /* pointer x and y */ @@ -515,10 +516,12 @@ static void ptrbutton(void *, struct wl_pointer *, uint32_t, uint32_t, uint32_t, uint32_t); static void ptraxis(void *, struct wl_pointer *, uint32_t, uint32_t, wl_fixed_t); -static void xdgshellping(void *, struct xdg_shell *, uint32_t); -static void xdgsurfconfigure(void *, struct xdg_surface *, - int32_t, int32_t, struct wl_array *, uint32_t); -static void xdgsurfclose(void *, struct xdg_surface *); +static void xdgshellping(void *, struct zxdg_shell_v6 *, uint32_t); +static void xdgsurfconfigure(void *, struct zxdg_surface_v6 *, + uint32_t); +static void xdgtoplevelconfigure(void *, struct zxdg_toplevel_v6 *, + int32_t, int32_t, struct wl_array *); +static void xdgtoplevelclose(void *, struct zxdg_toplevel_v6 *); static void datadevoffer(void *, struct wl_data_device *, struct wl_data_offer *); static void datadeventer(void *, struct wl_data_device *, uint32_t, @@ -565,9 +568,11 @@ static struct wl_keyboard_listener kbdlistener = { kbdkeymap, kbdenter, kbdleave, kbdkey, kbdmodifiers, kbdrepeatinfo }; static struct wl_pointer_listener ptrlistener = { ptrenter, ptrleave, ptrmotion, ptrbutton, ptraxis }; -static struct xdg_shell_listener xdgshelllistener = { xdgshellping }; -static struct xdg_surface_listener xdgsurflistener = - { xdgsurfconfigure, xdgsurfclose }; +static struct zxdg_shell_v6_listener xdgshelllistener = { xdgshellping }; +static struct zxdg_surface_v6_listener xdgsurflistener = + { xdgsurfconfigure }; +static struct zxdg_toplevel_v6_listener xdgtoplevellistener = + { xdgtoplevelconfigure, xdgtoplevelclose }; static struct wl_data_device_listener datadevlistener = { datadevoffer, datadeventer, datadevleave, datadevmotion, datadevdrop, datadevselection }; @@ -1231,7 +1236,7 @@ sigchld(int a) return; if (!WIFEXITED(stat) || WEXITSTATUS(stat)) - die("child finished with error '%d'\n", stat); + die("child finished with error '%d'\n", WEXITSTATUS(stat)); exit(0); } @@ -3408,9 +3413,13 @@ wlinit(void) wl.surface = wl_compositor_create_surface(wl.cmp); wl_surface_add_listener(wl.surface, &surflistener, NULL); - wl.xdgsurface = xdg_shell_get_xdg_surface(wl.shell, wl.surface); - xdg_surface_add_listener(wl.xdgsurface, &xdgsurflistener, NULL); - xdg_surface_set_app_id(wl.xdgsurface, opt_class ? opt_class : termname); + wl.xdgsurface = zxdg_shell_v6_get_xdg_surface(wl.shell, wl.surface); + zxdg_surface_v6_add_listener(wl.xdgsurface, &xdgsurflistener, NULL); + wl.xdgtoplevel = zxdg_surface_v6_get_toplevel(wl.xdgsurface); + zxdg_toplevel_v6_set_app_id(wl.xdgtoplevel, + opt_class ? opt_class : termname); + zxdg_toplevel_v6_add_listener(wl.xdgtoplevel, &xdgtoplevellistener, + NULL); wl.xkb.ctx = xkb_context_new(0); wlresettitle(); @@ -3779,7 +3788,7 @@ wldrawcursor(void) void wlsettitle(char *title) { - xdg_surface_set_title(wl.xdgsurface, title); + zxdg_toplevel_v6_set_title(wl.xdgtoplevel, title); } void @@ -3945,12 +3954,10 @@ regglobal(void *data, struct wl_registry *registry, uint32_t name, if (strcmp(interface, "wl_compositor") == 0) { wl.cmp = wl_registry_bind(registry, name, &wl_compositor_interface, 3); - } else if (strcmp(interface, "xdg_shell") == 0) { + } else if (strcmp(interface, "zxdg_shell_v6") == 0) { wl.shell = wl_registry_bind(registry, name, - &xdg_shell_interface, 1); - xdg_shell_add_listener(wl.shell, &xdgshelllistener, NULL); - xdg_shell_use_unstable_version(wl.shell, - XDG_SHELL_VERSION_CURRENT); + &zxdg_shell_v6_interface, 1); + zxdg_shell_v6_add_listener(wl.shell, &xdgshelllistener, NULL); } else if (strcmp(interface, "wl_shm") == 0) { wl.shm = wl_registry_bind(registry, name, &wl_shm_interface, 1); } else if (strcmp(interface, "wl_seat") == 0) { @@ -4293,27 +4300,44 @@ ptraxis(void * data, struct wl_pointer * pointer, uint32_t time, uint32_t axis, } void -xdgshellping(void *data, struct xdg_shell *shell, uint32_t serial) +xdgshellping(void *data, struct zxdg_shell_v6 *shell, uint32_t serial) +{ + zxdg_shell_v6_pong(shell, serial); +} + +void +xdgsurfconfigure(void *data, struct zxdg_surface_v6 *surf, uint32_t serial) { - xdg_shell_pong(shell, serial); + zxdg_surface_v6_ack_configure(surf, serial); } void -xdgsurfconfigure(void *data, struct xdg_surface *surf, int32_t w, int32_t h, - struct wl_array *states, uint32_t serial) +xdgtoplevelconfigure(void *data, struct zxdg_toplevel_v6 *toplevel, + int32_t w, int32_t h, struct wl_array *states) { - xdg_surface_ack_configure(surf, serial); - if (w == wl.w && h == wl.h) + + enum zxdg_toplevel_v6_state *state; + bool visible = 0; + wl_array_for_each(state, states) { + if(*state == ZXDG_TOPLEVEL_V6_STATE_ACTIVATED) visible = 1; + } + + if(visible) + wl.state |= WIN_VISIBLE; + else + wl.state &= ~WIN_VISIBLE; + + if(w == wl.w && h == wl.h) return; - cresize(w, h); - if (wl.configured) + cresize(w,h); + if(wl.configured) ttyresize(); else wl.configured = true; } void -xdgsurfclose(void *data, struct xdg_surface *surf) +xdgtoplevelclose(void *data, struct zxdg_toplevel_v6 *toplevel) { /* Send SIGHUP to shell */ kill(pid, SIGHUP); From 680909c69cad70914860b2bf48be67780ddd8ebe Mon Sep 17 00:00:00 2001 From: ethereal Date: Mon, 23 Jul 2018 15:48:45 -0400 Subject: [PATCH 110/129] Add wl_surface_commit() call, as Shugyousha pointed out. --- st.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/st.c b/st.c index d905620..8669b76 100644 --- a/st.c +++ b/st.c @@ -3421,6 +3421,8 @@ wlinit(void) zxdg_toplevel_v6_add_listener(wl.xdgtoplevel, &xdgtoplevellistener, NULL); + wl_surface_commit(wl.surface); + wl.xkb.ctx = xkb_context_new(0); wlresettitle(); } From 38c3b454543c8e51bd12cf1739b5d9ffe1dfe3c5 Mon Sep 17 00:00:00 2001 From: ian <42294085+ianbeyst@users.noreply.github.com> Date: Tue, 11 Jun 2019 17:09:55 +0200 Subject: [PATCH 111/129] Change xdg shell from unstable_v6 to stable st is now usable on velox/swc. Before, it gave a segfault on startup. --- Makefile | 10 +++++----- config.mk | 2 +- st.c | 56 +++++++++++++++++++++++++++---------------------------- 3 files changed, 34 insertions(+), 34 deletions(-) diff --git a/Makefile b/Makefile index af0a6c4..abbf225 100644 --- a/Makefile +++ b/Makefile @@ -3,7 +3,7 @@ include config.mk -SRC = st.c xdg-shell-unstable-v6-protocol.c +SRC = st.c xdg-shell-protocol.c OBJ = ${SRC:.c=.o} all: options st @@ -17,15 +17,15 @@ options: config.h: cp config.def.h config.h -xdg-shell-unstable-v6-protocol.c: +xdg-shell-protocol.c: @echo GEN $@ - @wayland-scanner code ${XDG_SHELL_PROTO} $@ + @wayland-scanner private-code ${XDG_SHELL_PROTO} $@ -xdg-shell-unstable-v6-client-protocol.h: +xdg-shell-client-protocol.h: @echo GEN $@ @wayland-scanner client-header ${XDG_SHELL_PROTO} $@ -st.o: xdg-shell-unstable-v6-client-protocol.h +st.o: xdg-shell-client-protocol.h .c.o: @echo CC $< diff --git a/config.mk b/config.mk index 61377c8..549a860 100644 --- a/config.mk +++ b/config.mk @@ -8,7 +8,7 @@ PREFIX = /usr/local MANPREFIX = ${PREFIX}/share/man PKGCFG = fontconfig wayland-client wayland-cursor xkbcommon wld -XDG_SHELL_PROTO = `pkg-config --variable=pkgdatadir wayland-protocols`/unstable/xdg-shell/xdg-shell-unstable-v6.xml +XDG_SHELL_PROTO = `pkg-config --variable=pkgdatadir wayland-protocols`/stable/xdg-shell/xdg-shell.xml # includes and libs INCS = -I. -I/usr/include `pkg-config --cflags ${PKGCFG}` diff --git a/st.c b/st.c index 8669b76..6a4a64c 100644 --- a/st.c +++ b/st.c @@ -33,7 +33,7 @@ #include #include "arg.h" -#include "xdg-shell-unstable-v6-client-protocol.h" +#include "xdg-shell-client-protocol.h" char *argv0; @@ -276,9 +276,9 @@ typedef struct { struct wl_data_offer *seloffer; struct wl_surface *surface; struct wl_buffer *buffer; - struct zxdg_shell_v6 *shell; - struct zxdg_surface_v6 *xdgsurface; - struct zxdg_toplevel_v6 *xdgtoplevel; + struct xdg_wm_base *shell; + struct xdg_surface *xdgsurface; + struct xdg_toplevel *xdgtoplevel; XKB xkb; bool configured; int px, py; /* pointer x and y */ @@ -516,12 +516,12 @@ static void ptrbutton(void *, struct wl_pointer *, uint32_t, uint32_t, uint32_t, uint32_t); static void ptraxis(void *, struct wl_pointer *, uint32_t, uint32_t, wl_fixed_t); -static void xdgshellping(void *, struct zxdg_shell_v6 *, uint32_t); -static void xdgsurfconfigure(void *, struct zxdg_surface_v6 *, +static void xdgshellping(void *, struct xdg_wm_base *, uint32_t); +static void xdgsurfconfigure(void *, struct xdg_surface *, uint32_t); -static void xdgtoplevelconfigure(void *, struct zxdg_toplevel_v6 *, +static void xdgtoplevelconfigure(void *, struct xdg_toplevel *, int32_t, int32_t, struct wl_array *); -static void xdgtoplevelclose(void *, struct zxdg_toplevel_v6 *); +static void xdgtoplevelclose(void *, struct xdg_toplevel *); static void datadevoffer(void *, struct wl_data_device *, struct wl_data_offer *); static void datadeventer(void *, struct wl_data_device *, uint32_t, @@ -568,10 +568,10 @@ static struct wl_keyboard_listener kbdlistener = { kbdkeymap, kbdenter, kbdleave, kbdkey, kbdmodifiers, kbdrepeatinfo }; static struct wl_pointer_listener ptrlistener = { ptrenter, ptrleave, ptrmotion, ptrbutton, ptraxis }; -static struct zxdg_shell_v6_listener xdgshelllistener = { xdgshellping }; -static struct zxdg_surface_v6_listener xdgsurflistener = +static struct xdg_wm_base_listener xdgshelllistener = { xdgshellping }; +static struct xdg_surface_listener xdgsurflistener = { xdgsurfconfigure }; -static struct zxdg_toplevel_v6_listener xdgtoplevellistener = +static struct xdg_toplevel_listener xdgtoplevellistener = { xdgtoplevelconfigure, xdgtoplevelclose }; static struct wl_data_device_listener datadevlistener = { datadevoffer, datadeventer, datadevleave, datadevmotion, datadevdrop, @@ -3413,12 +3413,12 @@ wlinit(void) wl.surface = wl_compositor_create_surface(wl.cmp); wl_surface_add_listener(wl.surface, &surflistener, NULL); - wl.xdgsurface = zxdg_shell_v6_get_xdg_surface(wl.shell, wl.surface); - zxdg_surface_v6_add_listener(wl.xdgsurface, &xdgsurflistener, NULL); - wl.xdgtoplevel = zxdg_surface_v6_get_toplevel(wl.xdgsurface); - zxdg_toplevel_v6_set_app_id(wl.xdgtoplevel, + wl.xdgsurface = xdg_wm_base_get_xdg_surface(wl.shell, wl.surface); + xdg_surface_add_listener(wl.xdgsurface, &xdgsurflistener, NULL); + wl.xdgtoplevel = xdg_surface_get_toplevel(wl.xdgsurface); + xdg_toplevel_set_app_id(wl.xdgtoplevel, opt_class ? opt_class : termname); - zxdg_toplevel_v6_add_listener(wl.xdgtoplevel, &xdgtoplevellistener, + xdg_toplevel_add_listener(wl.xdgtoplevel, &xdgtoplevellistener, NULL); wl_surface_commit(wl.surface); @@ -3790,7 +3790,7 @@ wldrawcursor(void) void wlsettitle(char *title) { - zxdg_toplevel_v6_set_title(wl.xdgtoplevel, title); + xdg_toplevel_set_title(wl.xdgtoplevel, title); } void @@ -3956,10 +3956,10 @@ regglobal(void *data, struct wl_registry *registry, uint32_t name, if (strcmp(interface, "wl_compositor") == 0) { wl.cmp = wl_registry_bind(registry, name, &wl_compositor_interface, 3); - } else if (strcmp(interface, "zxdg_shell_v6") == 0) { + } else if (strcmp(interface, "xdg_wm_base") == 0) { wl.shell = wl_registry_bind(registry, name, - &zxdg_shell_v6_interface, 1); - zxdg_shell_v6_add_listener(wl.shell, &xdgshelllistener, NULL); + &xdg_wm_base_interface, 1); + xdg_wm_base_add_listener(wl.shell, &xdgshelllistener, NULL); } else if (strcmp(interface, "wl_shm") == 0) { wl.shm = wl_registry_bind(registry, name, &wl_shm_interface, 1); } else if (strcmp(interface, "wl_seat") == 0) { @@ -4302,26 +4302,26 @@ ptraxis(void * data, struct wl_pointer * pointer, uint32_t time, uint32_t axis, } void -xdgshellping(void *data, struct zxdg_shell_v6 *shell, uint32_t serial) +xdgshellping(void *data, struct xdg_wm_base *shell, uint32_t serial) { - zxdg_shell_v6_pong(shell, serial); + xdg_wm_base_pong(shell, serial); } void -xdgsurfconfigure(void *data, struct zxdg_surface_v6 *surf, uint32_t serial) +xdgsurfconfigure(void *data, struct xdg_surface *surf, uint32_t serial) { - zxdg_surface_v6_ack_configure(surf, serial); + xdg_surface_ack_configure(surf, serial); } void -xdgtoplevelconfigure(void *data, struct zxdg_toplevel_v6 *toplevel, +xdgtoplevelconfigure(void *data, struct xdg_toplevel *toplevel, int32_t w, int32_t h, struct wl_array *states) { - enum zxdg_toplevel_v6_state *state; + enum xdg_toplevel_state *state; bool visible = 0; wl_array_for_each(state, states) { - if(*state == ZXDG_TOPLEVEL_V6_STATE_ACTIVATED) visible = 1; + if(*state == XDG_TOPLEVEL_STATE_ACTIVATED) visible = 1; } if(visible) @@ -4339,7 +4339,7 @@ xdgtoplevelconfigure(void *data, struct zxdg_toplevel_v6 *toplevel, } void -xdgtoplevelclose(void *data, struct zxdg_toplevel_v6 *toplevel) +xdgtoplevelclose(void *data, struct xdg_toplevel *toplevel) { /* Send SIGHUP to shell */ kill(pid, SIGHUP); From 02704541cf10767552b7c788a1cf0b79bdbb1f91 Mon Sep 17 00:00:00 2001 From: ian <42294085+ianbeyst@users.noreply.github.com> Date: Tue, 11 Jun 2019 17:23:22 +0200 Subject: [PATCH 112/129] make clean now removes autogenerated wayland protocol files --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index abbf225..5a3f668 100644 --- a/Makefile +++ b/Makefile @@ -39,7 +39,7 @@ st: ${OBJ} clean: @echo cleaning - @rm -f st ${OBJ} st-${VERSION}.tar.gz + @rm -f st ${OBJ} st-${VERSION}.tar.gz xdg-shell-protocol.c xdg-shell-client-protocol.h dist: clean @echo creating dist tarball From eb57fe757a0b856e0cc4bd1efbc437f9ce58a624 Mon Sep 17 00:00:00 2001 From: ian <42294085+ianbeyst@users.noreply.github.com> Date: Tue, 11 Jun 2019 17:44:27 +0200 Subject: [PATCH 113/129] Replaced all references to "st" by "st-wl" To prevent contaminating the already existing x11 st on my system. --- Makefile | 38 +++++++++++++++++++------------------- config.def.h | 12 ++++++------ st.1 => st-wl.1 | 36 ++++++++++++++++++------------------ st.c => st-wl.c | 24 ++++++++++++------------ st.info => st-wl.info | 14 +++++++------- 5 files changed, 62 insertions(+), 62 deletions(-) rename st.1 => st-wl.1 (84%) rename st.c => st-wl.c (99%) rename st.info => st-wl.info (94%) diff --git a/Makefile b/Makefile index 5a3f668..777c0dc 100644 --- a/Makefile +++ b/Makefile @@ -3,13 +3,13 @@ include config.mk -SRC = st.c xdg-shell-protocol.c +SRC = st-wl.c xdg-shell-protocol.c OBJ = ${SRC:.c=.o} -all: options st +all: options st-wl options: - @echo st build options: + @echo st-wl build options: @echo "CFLAGS = ${CFLAGS}" @echo "LDFLAGS = ${LDFLAGS}" @echo "CC = ${CC}" @@ -25,7 +25,7 @@ xdg-shell-client-protocol.h: @echo GEN $@ @wayland-scanner client-header ${XDG_SHELL_PROTO} $@ -st.o: xdg-shell-client-protocol.h +st-wl.o: xdg-shell-client-protocol.h .c.o: @echo CC $< @@ -33,38 +33,38 @@ st.o: xdg-shell-client-protocol.h ${OBJ}: config.h config.mk -st: ${OBJ} +st-wl: ${OBJ} @echo CC -o $@ @${CC} -o $@ ${OBJ} ${LDFLAGS} clean: @echo cleaning - @rm -f st ${OBJ} st-${VERSION}.tar.gz xdg-shell-protocol.c xdg-shell-client-protocol.h + @rm -f st-wl ${OBJ} st-wl-${VERSION}.tar.gz xdg-shell-protocol.c xdg-shell-client-protocol.h 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} + @mkdir -p st-wl-${VERSION} + @cp -R LICENSE Makefile README config.mk config.def.h st-wl.info st-wl.1 arg.h ${SRC} st-wl-${VERSION} + @tar -cf st-wl-${VERSION}.tar st-wl-${VERSION} + @gzip st-wl-${VERSION}.tar + @rm -rf st-wl-${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 + @cp -f st-wl ${DESTDIR}${PREFIX}/bin + @chmod 755 ${DESTDIR}${PREFIX}/bin/st-wl @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 - @echo Please see the README file regarding the terminfo entry of st. - @tic -sx st.info + @sed "s/VERSION/${VERSION}/g" < st-wl.1 > ${DESTDIR}${MANPREFIX}/man1/st-wl.1 + @chmod 644 ${DESTDIR}${MANPREFIX}/man1/st-wl.1 + @echo Please see the README file regarding the terminfo entry of st-wl. + @tic -sx st-wl.info uninstall: @echo removing executable file from ${DESTDIR}${PREFIX}/bin - @rm -f ${DESTDIR}${PREFIX}/bin/st + @rm -f ${DESTDIR}${PREFIX}/bin/st-wl @echo removing manual page from ${DESTDIR}${MANPREFIX}/man1 - @rm -f ${DESTDIR}${MANPREFIX}/man1/st.1 + @rm -f ${DESTDIR}${MANPREFIX}/man1/st-wl.1 .PHONY: all options clean dist install uninstall diff --git a/config.def.h b/config.def.h index 49ca50b..d3ae9cc 100644 --- a/config.def.h +++ b/config.def.h @@ -9,7 +9,7 @@ static char font[] = "Liberation Mono:pixelsize=12:antialias=true:autohint=true" static int borderpx = 2; /* - * What program is execed by st depends of these precedence rules: + * What program is execed by st-wl depends of these precedence rules: * 1: program passed with -e * 2: utmp option * 3: SHELL environment variable @@ -65,14 +65,14 @@ static unsigned int cursorthickness = 2; */ /* default TERM value */ -static char termname[] = "st-256color"; +static char termname[] = "st-wl-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. + * the st-wl.info and appropriately install the st-wl.info in the environment + * where you use this st-wl version. * * it#$tabspaces, * @@ -183,7 +183,7 @@ static Shortcut shortcuts[] = { }; /* - * Special keys (change & recompile st.info accordingly) + * Special keys (change & recompile st-wl.info accordingly) * * Mask value: * * Use MOD_MASK_ANY to match the key no matter modifiers state @@ -202,7 +202,7 @@ static Shortcut shortcuts[] = { * * > 0: crlf mode is enabled * * < 0: crlf mode is disabled * - * Be careful with the order of the definitions because st searches in + * Be careful with the order of the definitions because st-wl searches in * this table sequentially, so any MOD_MASK_ANY must be in the last * position for a key. */ diff --git a/st.1 b/st-wl.1 similarity index 84% rename from st.1 rename to st-wl.1 index c429dcf..c7faefb 100644 --- a/st.1 +++ b/st-wl.1 @@ -1,8 +1,8 @@ -.TH ST 1 st\-VERSION +.TH ST 1 st-wl\-VERSION .SH NAME -st \- simple terminal +st-wl \- simple terminal .SH SYNOPSIS -.B st +.B st-wl .RB [ \-aiv ] .RB [ \-c .IR class ] @@ -26,7 +26,7 @@ st \- simple terminal .IR command .RI [ arguments ...]] .PP -.B st +.B st-wl .RB [ \-aiv ] .RB [ \-c .IR class ] @@ -48,7 +48,7 @@ st \- simple terminal .IR line .RI [ stty_args ...] .SH DESCRIPTION -.B st +.B st-wl is a simple terminal emulator. .SH OPTIONS .TP @@ -61,7 +61,7 @@ defines the window class (default $TERM). .BI \-f " font" defines the .I font -to use when st is run. +to use when st-wl is run. .TP .BI \-g " geometry" defines the X11 geometry string. @@ -78,17 +78,17 @@ defines the window instance name (default $TERM). .BI \-o " iofile" writes all the I/O to .I iofile. -This feature is useful when recording st sessions. A value of "-" means +This feature is useful when recording st-wl sessions. A value of "-" means standard output. .TP .BI \-T " title" -defines the window title (default 'st'). +defines the window title (default 'st-wl'). .TP .BI \-t " title" -defines the window title (default 'st'). +defines the window title (default 'st-wl'). .TP .BI \-w " windowid" -embeds st within the window identified by +embeds st-wl within the window identified by .I windowid .TP .BI \-l " line" @@ -101,13 +101,13 @@ should be a (pseudo-)serial device (e.g. /dev/ttyS0 on Linux for serial port When this flag is given remaining arguments are used as flags for .BR stty(1). -By default st initializes the serial line to 8 bits, no parity, 1 stop bit +By default st-wl initializes the serial line to 8 bits, no parity, 1 stop bit and a 38400 baud rate. The speed is set by appending it as last argument -(e.g. 'st -l /dev/ttyS0 115200'). Arguments before the last one are +(e.g. 'st-wl -l /dev/ttyS0 115200'). Arguments before the last one are .BR stty(1) -flags. If you want to set odd parity on 115200 baud use for example 'st -l +flags. If you want to set odd parity on 115200 baud use for example 'st-wl -l /dev/ttyS0 parenb parodd 115200'. Set the number of bits by using for -example 'st -l /dev/ttyS0 cs7 115200'. See +example 'st-wl -l /dev/ttyS0 cs7 115200'. See .BR stty(1) for more arguments and cases. .TP @@ -115,7 +115,7 @@ for more arguments and cases. prints version information to stderr, then exits. .TP .BI \-e " command " [ " arguments " "... ]" -st executes +st-wl executes .I command instead of the shell. If this is used it .B must be the last option @@ -131,7 +131,7 @@ Break key is obtained in PC keyboards pressing at the same time control and pause. .TP .B Ctrl-Print Screen -Toggle if st should print to the +Toggle if st-wl should print to the .I iofile. .TP .B Shift-Print Screen @@ -165,9 +165,9 @@ Paste from the clipboard selection. .TP .B Alt-Ctrl Launch dmenu to enter a unicode codepoint and send the corresponding glyph -to st. +to st-wl. .SH CUSTOMIZATION -.B st +.B st-wl can be customized by creating a custom config.h and (re)compiling the source code. This keeps it fast, secure and simple. .SH AUTHORS diff --git a/st.c b/st-wl.c similarity index 99% rename from st.c rename to st-wl.c index 6a4a64c..11e6d78 100644 --- a/st.c +++ b/st-wl.c @@ -1071,7 +1071,7 @@ getsel(void) * The best solution seems like to produce '\n' when * something is copied from st and convert '\n' to * '\r', when something to be pasted is received by - * st. + * st-wl. * FIXME: Fix the computer world. */ if ((y < sel.ne.y || lastx >= linelen) && !(last->mode & ATTR_WRAP)) @@ -2890,7 +2890,7 @@ tputc(Rune u) if (strescseq.len+len >= sizeof(strescseq.buf)-1) { /* * Here is a bug in terminals. If the user never sends - * some code to stop the str or esc command, then st + * some code to stop the str or esc command, then st-wl * will stop responding. But this is better than * silently failing with unknown characters. At least * then users will report back. @@ -3203,7 +3203,7 @@ wlloadfont(Font *f, FcPattern *pattern) if ((FcPatternGetInteger(match, "slant", 0, &haveattr) != FcResultMatch) || haveattr < wantattr) { f->badslant = 1; - fputs("st: font slant does not match\n", stderr); + fputs("st-wl: font slant does not match\n", stderr); } } @@ -3212,7 +3212,7 @@ wlloadfont(Font *f, FcPattern *pattern) if ((FcPatternGetInteger(match, "weight", 0, &haveattr) != FcResultMatch) || haveattr != wantattr) { f->badweight = 1; - fputs("st: font weight does not match\n", stderr); + fputs("st-wl: font weight does not match\n", stderr); } } @@ -3248,7 +3248,7 @@ wlloadfonts(char *fontstr, double fontsize) } if (!pattern) - die("st: can't open font %s\n", fontstr); + die("st-wl: can't open font %s\n", fontstr); if (fontsize > 1) { FcPatternDel(pattern, FC_PIXEL_SIZE); @@ -3277,7 +3277,7 @@ wlloadfonts(char *fontstr, double fontsize) FcDefaultSubstitute(pattern); if (wlloadfont(&dc.font, pattern)) - die("st: can't open font %s\n", fontstr); + die("st-wl: can't open font %s\n", fontstr); if (usedfontsize < 0) { FcPatternGetDouble(dc.font.pattern, @@ -3294,17 +3294,17 @@ wlloadfonts(char *fontstr, double fontsize) FcPatternDel(pattern, FC_SLANT); FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ITALIC); if (wlloadfont(&dc.ifont, pattern)) - die("st: can't open font %s\n", fontstr); + die("st-wl: can't open font %s\n", fontstr); FcPatternDel(pattern, FC_WEIGHT); FcPatternAddInteger(pattern, FC_WEIGHT, FC_WEIGHT_BOLD); if (wlloadfont(&dc.ibfont, pattern)) - die("st: can't open font %s\n", fontstr); + die("st-wl: can't open font %s\n", fontstr); FcPatternDel(pattern, FC_SLANT); FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ROMAN); if (wlloadfont(&dc.bfont, pattern)) - die("st: can't open font %s\n", fontstr); + die("st-wl: can't open font %s\n", fontstr); FcPatternDestroy(pattern); } @@ -3740,7 +3740,7 @@ wldrawcursor(void) /* draw the new one */ if (wl.state & WIN_FOCUSED) { switch (wl.cursor) { - case 7: /* st extension: snowman */ + case 7: /* st-wl extension: snowman */ utf8decode("☃", &g.u, UTF_SIZ); case 0: /* Blinking Block */ case 1: /* Blinking Block (Default) */ @@ -3796,7 +3796,7 @@ wlsettitle(char *title) void wlresettitle(void) { - wlsettitle(opt_title ? opt_title : "st"); + wlsettitle(opt_title ? opt_title : "st-wl"); } void @@ -4562,7 +4562,7 @@ main(int argc, char *argv[]) opt_embed = EARGF(usage()); break; case 'v': - die("%s " VERSION " (c) 2010-2016 st engineers\n", argv0); + die("%s " VERSION " (c) 2010-2016 st-wl engineers\n", argv0); break; default: usage(); diff --git a/st.info b/st-wl.info similarity index 94% rename from st.info rename to st-wl.info index 13cc8eb..6506af9 100644 --- a/st.info +++ b/st-wl.info @@ -1,4 +1,4 @@ -st| simpleterm, +st-wl| simpleterm, acsc=+C\,D-A.B0E``aaffgghFiGjjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~, am, bce, @@ -190,24 +190,24 @@ st| simpleterm, Ss, Tc, -st-256color| simpleterm with 256 colors, - use=st, +st-wl-256color| simpleterm with 256 colors, + use=st-wl, colors#256, pairs#32767, # Nicked from xterm-256color 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, -st-meta| simpleterm with meta key, - use=st, +st-wl-meta| simpleterm with meta key, + use=st-wl, km, rmm=\E[?1034l, smm=\E[?1034h, rs2=\E[4l\E>\E[?1034h, is2=\E[4l\E>\E[?1034h, -st-meta-256color| simpleterm with meta key and 256 colors, - use=st-256color, +st-wl-meta-256color| simpleterm with meta key and 256 colors, + use=st-wl-256color, km, rmm=\E[?1034l, smm=\E[?1034h, From 24b6ab8f3e5109cd05f3f6edf5a5cbc1b22da9f2 Mon Sep 17 00:00:00 2001 From: ian <42294085+ianbeyst@users.noreply.github.com> Date: Wed, 12 Jun 2019 09:57:59 +0200 Subject: [PATCH 114/129] Removed toplevel configure state check that caused strange resize behaviour --- st-wl.c | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/st-wl.c b/st-wl.c index 11e6d78..d574640 100644 --- a/st-wl.c +++ b/st-wl.c @@ -4317,18 +4317,6 @@ void xdgtoplevelconfigure(void *data, struct xdg_toplevel *toplevel, int32_t w, int32_t h, struct wl_array *states) { - - enum xdg_toplevel_state *state; - bool visible = 0; - wl_array_for_each(state, states) { - if(*state == XDG_TOPLEVEL_STATE_ACTIVATED) visible = 1; - } - - if(visible) - wl.state |= WIN_VISIBLE; - else - wl.state &= ~WIN_VISIBLE; - if(w == wl.w && h == wl.h) return; cresize(w,h); From 7eaafe4a70d9b20007211229c213ef8709312cc2 Mon Sep 17 00:00:00 2001 From: ian <42294085+ianbeyst@users.noreply.github.com> Date: Wed, 12 Jun 2019 10:40:34 +0200 Subject: [PATCH 115/129] Whitespace, variable names and gitignore To partially harmonize with michaelforney's st patch at https://github.com/michaelforney/oasis/blob/master/pkg/st/patch/0001-Port-to-wayland-using-wld.patch --- .gitignore | 1 + st-wl.c | 49 ++++++++++++++++++++++--------------------------- 2 files changed, 23 insertions(+), 27 deletions(-) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0e56cf2 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +config.h diff --git a/st-wl.c b/st-wl.c index d574640..40415b3 100644 --- a/st-wl.c +++ b/st-wl.c @@ -276,7 +276,7 @@ typedef struct { struct wl_data_offer *seloffer; struct wl_surface *surface; struct wl_buffer *buffer; - struct xdg_wm_base *shell; + struct xdg_wm_base *wm; struct xdg_surface *xdgsurface; struct xdg_toplevel *xdgtoplevel; XKB xkb; @@ -516,9 +516,8 @@ static void ptrbutton(void *, struct wl_pointer *, uint32_t, uint32_t, uint32_t, uint32_t); static void ptraxis(void *, struct wl_pointer *, uint32_t, uint32_t, wl_fixed_t); -static void xdgshellping(void *, struct xdg_wm_base *, uint32_t); -static void xdgsurfconfigure(void *, struct xdg_surface *, - uint32_t); +static void wmping(void *, struct xdg_wm_base *, uint32_t); +static void xdgsurfconfigure(void *, struct xdg_surface *, uint32_t); static void xdgtoplevelconfigure(void *, struct xdg_toplevel *, int32_t, int32_t, struct wl_array *); static void xdgtoplevelclose(void *, struct xdg_toplevel *); @@ -568,9 +567,8 @@ static struct wl_keyboard_listener kbdlistener = { kbdkeymap, kbdenter, kbdleave, kbdkey, kbdmodifiers, kbdrepeatinfo }; static struct wl_pointer_listener ptrlistener = { ptrenter, ptrleave, ptrmotion, ptrbutton, ptraxis }; -static struct xdg_wm_base_listener xdgshelllistener = { xdgshellping }; -static struct xdg_surface_listener xdgsurflistener = - { xdgsurfconfigure }; +static struct xdg_wm_base_listener wmlistener = { wmping }; +static struct xdg_surface_listener xdgsurflistener = { xdgsurfconfigure }; static struct xdg_toplevel_listener xdgtoplevellistener = { xdgtoplevelconfigure, xdgtoplevelclose }; static struct wl_data_device_listener datadevlistener = @@ -3386,8 +3384,10 @@ wlinit(void) die("Display has no seat\n"); if (!wl.datadevmanager) die("Display has no data device manager\n"); + if (!wl.wm) + die("Display has no window manager\n"); - wl.keyboard = wl_seat_get_keyboard(wl.seat); + wl.keyboard = wl_seat_get_keyboard(wl.seat); wl_keyboard_add_listener(wl.keyboard, &kbdlistener, NULL); wl.pointer = wl_seat_get_pointer(wl.seat); wl_pointer_add_listener(wl.pointer, &ptrlistener, NULL); @@ -3413,15 +3413,13 @@ wlinit(void) wl.surface = wl_compositor_create_surface(wl.cmp); wl_surface_add_listener(wl.surface, &surflistener, NULL); - wl.xdgsurface = xdg_wm_base_get_xdg_surface(wl.shell, wl.surface); + wl.xdgsurface = xdg_wm_base_get_xdg_surface(wl.wm, wl.surface); xdg_surface_add_listener(wl.xdgsurface, &xdgsurflistener, NULL); wl.xdgtoplevel = xdg_surface_get_toplevel(wl.xdgsurface); - xdg_toplevel_set_app_id(wl.xdgtoplevel, - opt_class ? opt_class : termname); - xdg_toplevel_add_listener(wl.xdgtoplevel, &xdgtoplevellistener, - NULL); + xdg_toplevel_add_listener(wl.xdgtoplevel, &xdgtoplevellistener, NULL); + xdg_toplevel_set_app_id(wl.xdgtoplevel, opt_class ? opt_class : termname); - wl_surface_commit(wl.surface); + wl_surface_commit(wl.surface); wl.xkb.ctx = xkb_context_new(0); wlresettitle(); @@ -3954,17 +3952,14 @@ regglobal(void *data, struct wl_registry *registry, uint32_t name, const char *interface, uint32_t version) { if (strcmp(interface, "wl_compositor") == 0) { - wl.cmp = wl_registry_bind(registry, name, - &wl_compositor_interface, 3); + wl.cmp = wl_registry_bind(registry, name, &wl_compositor_interface, 3); } else if (strcmp(interface, "xdg_wm_base") == 0) { - wl.shell = wl_registry_bind(registry, name, - &xdg_wm_base_interface, 1); - xdg_wm_base_add_listener(wl.shell, &xdgshelllistener, NULL); + wl.wm = wl_registry_bind(registry, name, &xdg_wm_base_interface, 1); + xdg_wm_base_add_listener(wl.wm, &wmlistener, NULL); } else if (strcmp(interface, "wl_shm") == 0) { wl.shm = wl_registry_bind(registry, name, &wl_shm_interface, 1); } else if (strcmp(interface, "wl_seat") == 0) { - wl.seat = wl_registry_bind(registry, name, - &wl_seat_interface, 4); + wl.seat = wl_registry_bind(registry, name, &wl_seat_interface, 4); } else if (strcmp(interface, "wl_data_device_manager") == 0) { wl.datadevmanager = wl_registry_bind(registry, name, &wl_data_device_manager_interface, 1); @@ -4302,9 +4297,9 @@ ptraxis(void * data, struct wl_pointer * pointer, uint32_t time, uint32_t axis, } void -xdgshellping(void *data, struct xdg_wm_base *shell, uint32_t serial) +wmping(void *data, struct xdg_wm_base *wm, uint32_t serial) { - xdg_wm_base_pong(shell, serial); + xdg_wm_base_pong(wm, serial); } void @@ -4315,12 +4310,12 @@ xdgsurfconfigure(void *data, struct xdg_surface *surf, uint32_t serial) void xdgtoplevelconfigure(void *data, struct xdg_toplevel *toplevel, - int32_t w, int32_t h, struct wl_array *states) + int32_t w, int32_t h, struct wl_array *states) { - if(w == wl.w && h == wl.h) + if (w == wl.w && h == wl.h) return; - cresize(w,h); - if(wl.configured) + cresize(w, h); + if (wl.configured) ttyresize(); else wl.configured = true; From 5ca2e612e7678147b1b34fc2f832f63042809193 Mon Sep 17 00:00:00 2001 From: ian <42294085+ianbeyst@users.noreply.github.com> Date: Wed, 12 Jun 2019 21:59:40 +0200 Subject: [PATCH 116/129] Initial work on split implementation similar to upstream st crude first steps to move the wayland stack to a state where it becomes easy to track upstream st. Most wayland related functions are separated out and the program compiles and runs. Further work is needed to flesh out bugs, clean up the messy code and eventually merge with upstream. --- Makefile | 7 +- config.def.h | 64 +- st-wl.c | 1872 ++------------------------------------------------ st-wl.h | 387 +++++++++++ wl.c | 1581 ++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 2048 insertions(+), 1863 deletions(-) create mode 100644 st-wl.h create mode 100644 wl.c diff --git a/Makefile b/Makefile index 777c0dc..99b91b3 100644 --- a/Makefile +++ b/Makefile @@ -3,7 +3,7 @@ include config.mk -SRC = st-wl.c xdg-shell-protocol.c +SRC = st-wl.c wl.c xdg-shell-protocol.c OBJ = ${SRC:.c=.o} all: options st-wl @@ -25,12 +25,13 @@ xdg-shell-client-protocol.h: @echo GEN $@ @wayland-scanner client-header ${XDG_SHELL_PROTO} $@ -st-wl.o: xdg-shell-client-protocol.h - .c.o: @echo CC $< @${CC} -c ${CFLAGS} $< +st-wl.o: st-wl.h xdg-shell-client-protocol.h +wl.o: st-wl.h xdg-shell-client-protocol.h + ${OBJ}: config.h config.mk st-wl: ${OBJ} diff --git a/config.def.h b/config.def.h index d3ae9cc..5a25732 100644 --- a/config.def.h +++ b/config.def.h @@ -5,8 +5,8 @@ * * font: see http://freedesktop.org/software/fontconfig/fontconfig-user.html */ -static char font[] = "Liberation Mono:pixelsize=12:antialias=true:autohint=true"; -static int borderpx = 2; +char font[] = "Liberation Mono:pixelsize=12:antialias=true:autohint=true"; +int borderpx = 2; /* * What program is execed by st-wl depends of these precedence rules: @@ -24,8 +24,8 @@ static char stty_args[] = "stty raw pass8 nl -echo -iexten -cstopb 38400"; static char vtiden[] = "\033[?6c"; /* Kerning / character bounding-box multipliers */ -static float cwscale = 1.0; -static float chscale = 1.0; +float cwscale = 1.0; +float chscale = 1.0; /* * word delimiter string @@ -35,26 +35,26 @@ static float chscale = 1.0; static char worddelimiters[] = " "; /* selection timeouts (in milliseconds) */ -static unsigned int doubleclicktimeout = 300; -static unsigned int tripleclicktimeout = 600; +unsigned int doubleclicktimeout = 300; +unsigned int tripleclicktimeout = 600; /* key repeat timeouts (in milliseconds) */ -static unsigned int keyrepeatdelay = 500; -static unsigned int keyrepeatinterval = 25; +unsigned int keyrepeatdelay = 500; +unsigned int keyrepeatinterval = 25; /* alt screens */ -static int allowaltscreen = 1; +int allowaltscreen = 1; /* * blinking timeout (set to 0 to disable blinking) for the terminal blinking * attribute. */ -static unsigned int blinktimeout = 800; +unsigned int blinktimeout = 800; /* * thickness of underline and bar cursors */ -static unsigned int cursorthickness = 2; +unsigned int cursorthickness = 2; /* * bell volume. It must be a value between -100 and 100. Use 0 for disabling @@ -65,7 +65,7 @@ static unsigned int cursorthickness = 2; */ /* default TERM value */ -static char termname[] = "st-wl-256color"; +char termname[] = "st-wl-256color"; /* * spaces per tab @@ -82,10 +82,10 @@ static char termname[] = "st-wl-256color"; * * stty tabs */ -static unsigned int tabspaces = 8; +unsigned int tabspaces = 8; /* Terminal colors (16 first used in escape sequence) */ -static const char *colorname[] = { +const char *colorname[] = { /* 8 normal colors */ "black", "red3", @@ -118,10 +118,10 @@ static const char *colorname[] = { * 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; +unsigned int defaultfg = 7; +unsigned int defaultbg = 0; +unsigned int defaultcs = 256; +unsigned int defaultrcs = 257; /* * Default shape of cursor @@ -130,36 +130,36 @@ static unsigned int defaultrcs = 257; * 6: Bar ("|") * 7: Snowman ("☃") */ -static unsigned int cursorshape = 2; +unsigned int cursorshape = 2; /* * Default columns and rows numbers */ -static unsigned int cols = 80; -static unsigned int rows = 24; +unsigned int cols = 80; +unsigned int rows = 24; /* * Default shape of the mouse cursor */ -static char mouseshape[] = "xterm"; +char mouseshape[] = "xterm"; /* * Color used to display font attributes when fontconfig selected a font which * doesn't match the ones requested. */ -static unsigned int defaultattr = 11; +unsigned int defaultattr = 11; /* * Internal mouse shortcuts. * Beware that overloading Button1 will disable the selection. */ -static MouseShortcut mshortcuts[] = { +MouseShortcut mshortcuts[] = { /* button mask string */ { -1, MOD_MASK_NONE, "" } }; -static Axiskey ashortcuts[] = { +Axiskey ashortcuts[] = { /* axis direction mask string */ { AXIS_VERTICAL, +1, MOD_MASK_ANY, "\031"}, { AXIS_VERTICAL, -1, MOD_MASK_ANY, "\005"}, @@ -168,7 +168,7 @@ static Axiskey ashortcuts[] = { /* Internal keyboard shortcuts. */ #define MODKEY MOD_MASK_ALT -static Shortcut shortcuts[] = { +Shortcut shortcuts[] = { /* modifier key function argument */ { MOD_MASK_ANY, XKB_KEY_Break, sendbreak, {.i = 0} }, { MOD_MASK_CTRL, XKB_KEY_Print, toggleprinter, {.i = 0} }, @@ -211,23 +211,23 @@ static Shortcut shortcuts[] = { * If you want keys other than the X11 function keys (0xFD00 - 0xFFFF) * to be mapped below, add them to this array. */ -static xkb_keysym_t mappedkeys[] = { -1 }; +xkb_keysym_t mappedkeys[] = { -1 }; /* State bits to ignore when matching key or button events. */ -static uint ignoremod = 0; +uint ignoremod = 0; /* * Override mouse-select while mask is active (when MODE_MOUSE is set). * Note that if you want to use MOD_MASK_SHIFT with selmasks, set this to an * other modifier, set to 0 to not use it. */ -static uint forceselmod = MOD_MASK_SHIFT; +uint forceselmod = MOD_MASK_SHIFT; /* * This is the huge key array which defines all compatibility to the Linux * world. Please decide about changes wisely. */ -static Key key[] = { +Key key[] = { /* keysym mask string appkey appcursor crlf */ { XKB_KEY_KP_Home, MOD_MASK_SHIFT, "\033[2J", 0, -1, 0}, { XKB_KEY_KP_Home, MOD_MASK_SHIFT, "\033[1;2H", 0, +1, 0}, @@ -447,7 +447,7 @@ static Key key[] = { * ButtonRelease and MotionNotify. * If no match is found, regular selection is used. */ -static uint selmasks[] = { +uint selmasks[] = { [SEL_RECTANGULAR] = MOD_MASK_ALT, }; @@ -455,7 +455,7 @@ static uint selmasks[] = { * Printable characters in ASCII, used to estimate the advance width * of single wide characters. */ -static char ascii_printable[] = +char ascii_printable[] = " !\"#$%&'()*+,-./0123456789:;<=>?" "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_" "`abcdefghijklmnopqrstuvwxyz{|}~"; diff --git a/st-wl.c b/st-wl.c index 40415b3..4eadd82 100644 --- a/st-wl.c +++ b/st-wl.c @@ -37,6 +37,8 @@ char *argv0; +#include "st-wl.h" + #if defined(__linux) #include #elif defined(__OpenBSD__) || defined(__NetBSD__) || defined(__APPLE__) @@ -48,8 +50,6 @@ char *argv0; /* Arbitrary sizes */ #define UTF_INVALID 0xFFFD -#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 @@ -58,37 +58,18 @@ char *argv0; #define XK_NO_MOD 0 #define XK_SWITCH_MOD (1<<13) -#define MOD_MASK_ANY UINT_MAX -#define MOD_MASK_NONE 0 -#define MOD_MASK_CTRL (1<<0) -#define MOD_MASK_ALT (1<<1) -#define MOD_MASK_SHIFT (1<<2) -#define MOD_MASK_LOGO (1<<3) - -#define AXIS_VERTICAL WL_POINTER_AXIS_VERTICAL_SCROLL #define AXIS_HORIZONTAL WL_POINTER_AXIS_HORIZONTAL_SCROLL /* 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 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 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) @@ -96,22 +77,6 @@ char *argv0; /* constants */ #define ISO14755CMD "dmenu -p codepoint: ] [;]] []] */ typedef struct { @@ -237,185 +130,16 @@ typedef struct { int narg; /* nb of args */ } STREscape; -/* 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 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 numlock; /* lock numbers in keyboard */ - int *tabs; -} Term; - -typedef struct { - struct xkb_context *ctx; - struct xkb_keymap *keymap; - struct xkb_state *state; - xkb_mod_index_t ctrl, alt, shift, logo; - unsigned int mods; -} XKB; - -typedef struct { - struct wl_display *dpy; - struct wl_compositor *cmp; - struct wl_shm *shm; - struct wl_seat *seat; - struct wl_keyboard *keyboard; - struct wl_pointer *pointer; - struct wl_data_device_manager *datadevmanager; - struct wl_data_device *datadev; - struct wl_data_offer *seloffer; - struct wl_surface *surface; - struct wl_buffer *buffer; - struct xdg_wm_base *wm; - struct xdg_surface *xdgsurface; - struct xdg_toplevel *xdgtoplevel; - XKB xkb; - bool configured; - int px, py; /* pointer x and y */ - int tw, th; /* tty width and height */ - int w, h; /* window width and height */ - int ch; /* char height */ - int cw; /* char width */ - int vis; - char state; /* focus, redraw, visible */ - int cursor; /* cursor style */ - struct wl_callback * framecb; -} Wayland; - -typedef struct { - struct wld_context *ctx; - struct wld_font_context *fontctx; - struct wld_renderer *renderer; - struct wld_buffer *buffer, *oldbuffer; -} WLD; - -typedef struct { - struct wl_cursor_theme *theme; - struct wl_cursor *cursor; - struct wl_surface *surface; -} Cursor; - -typedef struct { - uint b; - uint mask; - char *s; -} MouseShortcut; - -typedef struct { - int axis; - int dir; - uint mask; - char s[ESC_BUF_SIZ]; -} Axiskey; - -typedef struct { - xkb_keysym_t 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; - -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; - struct wl_data_source *source; - int alt; - uint32_t tclick1, tclick2; -} Selection; - -typedef union { - int i; - uint ui; - float f; - const void *v; -} Arg; - -typedef struct { - uint mod; - xkb_keysym_t keysym; - void (*func)(const Arg *); - const Arg arg; -} Shortcut; -typedef struct { - char str[32]; - uint32_t key; - int len; - bool started; - struct timespec last; -} Repeat; - -/* function definitions used in config.h */ -static void numlock(const Arg *); -static void selpaste(const Arg *); -static void wlzoom(const Arg *); -static void wlzoomabs(const Arg *); -static void wlzoomreset(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; - struct wld_font *match; - FcFontSet *set; - FcPattern *pattern; -} Font; - -/* Drawing Context */ -typedef struct { - uint32_t col[MAX(LEN(colorname), 256)]; - Font font, bfont, ifont, ibfont; -} 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 sigchld(int); -static void run(void); -static void cresize(int, int); static void csidump(void); static void csihandle(void); @@ -427,7 +151,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); @@ -441,8 +164,6 @@ 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); @@ -453,8 +174,6 @@ static void tsetattr(int *, int); static void tsetchar(Rune, Glyph *, 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 void tfulldirt(void); static void techo(Rune); @@ -463,172 +182,65 @@ 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 uchar sixd_to_8bit(int); -static void wldraws(char *, Glyph, int, int, int, int); -static void wldrawglyph(Glyph, int, int); -static void wlclear(int, int, int, int); -static void wldrawcursor(void); -static void wlinit(void); -static void wlloadcols(void); -static int wlsetcolorname(int, const char *); -static void wlloadcursor(void); -static int wlloadfont(Font *, FcPattern *); -static void wlloadfonts(char *, double); -static void wlsettitle(char *); -static void wlresettitle(void); static void wlseturgency(int); static void wlsetsel(char*, uint32_t); -static void wlunloadfont(Font *f); -static void wlunloadfonts(void); -static void wlresize(int, int); - -static void regglobal(void *, struct wl_registry *, uint32_t, const char *, - uint32_t); -static void regglobalremove(void *, struct wl_registry *, uint32_t); -static void surfenter(void *, struct wl_surface *, struct wl_output *); -static void surfleave(void *, struct wl_surface *, struct wl_output *); -static void framedone(void *, struct wl_callback *, uint32_t); -static void kbdkeymap(void *, struct wl_keyboard *, uint32_t, int32_t, uint32_t); -static void kbdenter(void *, struct wl_keyboard *, uint32_t, - struct wl_surface *, struct wl_array *); -static void kbdleave(void *, struct wl_keyboard *, uint32_t, - struct wl_surface *); -static void kbdkey(void *, struct wl_keyboard *, uint32_t, uint32_t, uint32_t, - uint32_t); -static void kbdmodifiers(void *, struct wl_keyboard *, uint32_t, uint32_t, - uint32_t, uint32_t, uint32_t); -static void kbdrepeatinfo(void *, struct wl_keyboard *, int32_t, int32_t); -static void ptrenter(void *, struct wl_pointer *, uint32_t, struct wl_surface *, - wl_fixed_t, wl_fixed_t); -static void ptrleave(void *, struct wl_pointer *, uint32_t, - struct wl_surface *); -static void ptrmotion(void *, struct wl_pointer *, uint32_t, - wl_fixed_t, wl_fixed_t); -static void ptrbutton(void *, struct wl_pointer *, uint32_t, uint32_t, - uint32_t, uint32_t); -static void ptraxis(void *, struct wl_pointer *, uint32_t, uint32_t, - wl_fixed_t); -static void wmping(void *, struct xdg_wm_base *, uint32_t); -static void xdgsurfconfigure(void *, struct xdg_surface *, uint32_t); -static void xdgtoplevelconfigure(void *, struct xdg_toplevel *, - int32_t, int32_t, struct wl_array *); -static void xdgtoplevelclose(void *, struct xdg_toplevel *); -static void datadevoffer(void *, struct wl_data_device *, - struct wl_data_offer *); -static void datadeventer(void *, struct wl_data_device *, uint32_t, - struct wl_surface *, wl_fixed_t, wl_fixed_t, struct wl_data_offer *); -static void datadevleave(void *, struct wl_data_device *); -static void datadevmotion(void *, struct wl_data_device *, uint32_t, - wl_fixed_t x, wl_fixed_t y); -static void datadevdrop(void *, struct wl_data_device *); -static void datadevselection(void *, struct wl_data_device *, - struct wl_data_offer *); -static void dataofferoffer(void *, struct wl_data_offer *, const char *); -static void datasrctarget(void *, struct wl_data_source *, const char *); -static void datasrcsend(void *, struct wl_data_source *, const char *, int32_t); -static void datasrccancelled(void *, struct wl_data_source *); - -static void selinit(void); -static void selnormalize(void); -static inline int selected(int, int); + static char *getsel(void); -static void selcopy(uint32_t); static void selscroll(int, int); static void selsnap(int *, int *, int); -static int x2col(int); -static int y2row(int); -static size_t utf8decode(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 size_t utf8validate(Rune *, size_t); 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); +/* Globals */ +Wayland wl; +WLD wld; +static CSIEscape csiescseq; +static STREscape strescseq; +pid_t pid; +Selection sel; +bool needdraw = true; +static int iofd = 1; +char **opt_cmd = NULL; +char *opt_class = NULL; +char *opt_embed = NULL; +char *opt_font = NULL; +char *opt_io = NULL; +char *opt_line = NULL; +char *opt_name = NULL; +char *opt_title = NULL; + +char *usedfont = NULL; +double usedfontsize = 0; +double defaultfontsize = 0; -static struct wl_registry_listener reglistener = { regglobal, regglobalremove }; -static struct wl_surface_listener surflistener = { surfenter, surfleave }; static struct wl_callback_listener framelistener = { framedone }; -static struct wl_keyboard_listener kbdlistener = - { kbdkeymap, kbdenter, kbdleave, kbdkey, kbdmodifiers, kbdrepeatinfo }; -static struct wl_pointer_listener ptrlistener = - { ptrenter, ptrleave, ptrmotion, ptrbutton, ptraxis }; -static struct xdg_wm_base_listener wmlistener = { wmping }; -static struct xdg_surface_listener xdgsurflistener = { xdgsurfconfigure }; -static struct xdg_toplevel_listener xdgtoplevellistener = - { xdgtoplevelconfigure, xdgtoplevelclose }; -static struct wl_data_device_listener datadevlistener = - { datadevoffer, datadeventer, datadevleave, datadevmotion, datadevdrop, - datadevselection }; static struct wl_data_offer_listener dataofferlistener = { dataofferoffer }; static struct wl_data_source_listener datasrclistener = - { datasrctarget, datasrcsend, datasrccancelled }; + { datasrctarget, datasrcsend, datasrccancelled }; -/* Globals */ -static DC dc; -static Wayland wl; -static WLD wld; -static Cursor cursor; -static Term term; -static CSIEscape csiescseq; -static STREscape strescseq; -static int cmdfd; -static pid_t pid; -static Selection sel; -static Repeat repeat; -static bool needdraw = true; -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 oldx, oldy; - -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 { - struct wld_font *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; +/* config.h array lengths */ +size_t colornamelen = LEN(colorname); +size_t maxcolornamelen = MAX(LEN(colorname), 256); +size_t mshortcutslen = LEN(mshortcuts); +size_t ashortcutslen = LEN(ashortcuts); +size_t shortcutslen = LEN(shortcuts); +size_t selmaskslen = LEN(selmasks); +size_t mappedkeyslen = LEN(mappedkeys); +size_t keylen = LEN(key); ssize_t xwrite(int fd, const char *s, size_t len) @@ -775,24 +387,6 @@ selinit(void) sel.source = NULL; } -int -x2col(int x) -{ - x -= borderpx; - x /= wl.cw; - - return LIMIT(x, 0, term.col-1); -} - -int -y2row(int y) -{ - y -= borderpx; - y /= wl.ch; - - return LIMIT(y, 0, term.row-1); -} - int tlinelen(int y) { @@ -923,108 +517,6 @@ selsnap(int *x, int *y, int direction) } } -void -getbuttoninfo(void) -{ - int type; - uint state = wl.xkb.mods & ~forceselmod; - - sel.alt = IS_SET(MODE_ALTSCREEN); - - sel.oe.x = x2col(wl.px); - sel.oe.y = y2row(wl.py); - selnormalize(); - - sel.type = SEL_REGULAR; - for (type = 1; type < LEN(selmasks); ++type) { - if (match(selmasks[type], state)) { - sel.type = type; - break; - } - } -} - -void -wlmousereport(int button, bool release, int x, int y) -{ - int len; - char buf[40]; - - if (!IS_SET(MODE_MOUSEX10)) { - button += ((wl.xkb.mods & MOD_MASK_SHIFT) ? 4 : 0) - + ((wl.xkb.mods & MOD_MASK_LOGO ) ? 8 : 0) - + ((wl.xkb.mods & MOD_MASK_CTRL ) ? 16 : 0); - } - - if (IS_SET(MODE_MOUSESGR)) { - len = snprintf(buf, sizeof(buf), "\033[<%d;%d;%d%c", - button, x+1, y+1, release ? '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 -wlmousereportbutton(uint32_t button, uint32_t state) -{ - bool release = state == WL_POINTER_BUTTON_STATE_RELEASED; - - if (!IS_SET(MODE_MOUSESGR) && release) { - button = 3; - } else { - switch (button) { - case BTN_LEFT: - button = 0; - break; - case BTN_MIDDLE: - button = 1; - break; - case BTN_RIGHT: - button = 2; - break; - } - } - - oldbutton = release ? 3 : button; - - /* don't report release events when in X10 mode */ - if (IS_SET(MODE_MOUSEX10) && release) { - return; - } - - wlmousereport(button, release, oldx, oldy); -} - -void -wlmousereportmotion(wl_fixed_t fx, wl_fixed_t fy) -{ - int x = x2col(wl_fixed_to_int(fx)), y = y2row(wl_fixed_to_int(fy)); - - if (x == oldx && y == oldy) - 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; - - oldx = x; - oldy = y; - wlmousereport(oldbutton + 32, false, x, y); -} - -void -wlmousereportaxis(uint32_t axis, wl_fixed_t amount) -{ - wlmousereport(64 + (axis == AXIS_VERTICAL ? 4 : 6) - + (amount > 0 ? 1 : 0), false, oldx, oldy); -} - char * getsel(void) { @@ -3064,271 +2556,6 @@ tresize(int col, int row) term.c = c; } -void -wlresize(int col, int row) -{ - union wld_object object; - - wl.tw = MAX(1, col * wl.cw); - wl.th = MAX(1, row * wl.ch); - - wld.oldbuffer = wld.buffer; - wld.buffer = wld_create_buffer(wld.ctx, wl.w, wl.h, - WLD_FORMAT_XRGB8888, 0); - wld_export(wld.buffer, WLD_WAYLAND_OBJECT_BUFFER, &object); - wl.buffer = object.ptr; -} - -uchar -sixd_to_8bit(int x) -{ - return x == 0 ? 0 : 0x37 + 0x28 * x; -} - -int -wlloadcolor(int i, const char *name, uint32_t *color) -{ - if (!name) { - if (BETWEEN(i, 16, 255)) { /* 256 color */ - if (i < 6*6*6+16) { /* same colors as xterm */ - *color = 0xff << 24 | sixd_to_8bit(((i-16)/36)%6) << 16 - | sixd_to_8bit(((i-16)/6)%6) << 8 - | sixd_to_8bit(((i-16)/1)%6); - } else { /* greyscale */ - *color = 0xff << 24 | (0x8 + 0xa * (i-(6*6*6+16))) * 0x10101; - } - return true; - } else - name = colorname[i]; - } - - return wld_lookup_named_color(name, color); -} - -void -wlloadcols(void) -{ - int i; - - for (i = 0; i < LEN(dc.col); i++) - if (!wlloadcolor(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); - } -} - -int -wlsetcolorname(int x, const char *name) -{ - uint32_t color; - - if (!BETWEEN(x, 0, LEN(dc.col))) - return 1; - - if (!wlloadcolor(x, name, &color)) - return 1; - - dc.col[x] = color; - - return 0; -} - -static void wlloadcursor(void) -{ - char *names[] = { mouseshape, "xterm", "ibeam", "text" }; - int i; - - cursor.theme = wl_cursor_theme_load(NULL, 32, wl.shm); - - for (i = 0; !cursor.cursor && i < LEN(names); i++) - cursor.cursor = wl_cursor_theme_get_cursor(cursor.theme, names[i]); - - cursor.surface = wl_compositor_create_surface(wl.cmp); -} - -/* - * Absolute coordinates. - */ -void -wlclear(int x1, int y1, int x2, int y2) -{ - uint32_t color = dc.col[IS_SET(MODE_REVERSE) ? defaultfg : defaultbg]; - - wld_fill_rectangle(wld.renderer, color, x1, y1, x2 - x1, y2 - y1); -} - -int -wlloadfont(Font *f, FcPattern *pattern) -{ - FcPattern *configured; - FcPattern *match; - FcResult result; - struct wld_extents 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); - FcDefaultSubstitute(configured); - - match = FcFontMatch(NULL, configured, &result); - if (!match) { - FcPatternDestroy(configured); - return 1; - } - - if (!(f->match = wld_font_open_pattern(wld.fontctx, match))) { - FcPatternDestroy(configured); - FcPatternDestroy(match); - return 1; - } - - if ((FcPatternGetInteger(pattern, "slant", 0, &wantattr) == - FcResultMatch)) { - /* - * Check if xft was unable to find a font with the appropriate - * slant but gave us one anyway. Try to mitigate. - */ - if ((FcPatternGetInteger(match, "slant", 0, - &haveattr) != FcResultMatch) || haveattr < wantattr) { - f->badslant = 1; - fputs("st-wl: font slant does not match\n", stderr); - } - } - - if ((FcPatternGetInteger(pattern, "weight", 0, &wantattr) == - FcResultMatch)) { - if ((FcPatternGetInteger(match, "weight", 0, - &haveattr) != FcResultMatch) || haveattr != wantattr) { - f->badweight = 1; - fputs("st-wl: font weight does not match\n", stderr); - } - } - - - wld_font_text_extents(f->match, 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; - - f->height = f->ascent + f->descent; - f->width = DIVCEIL(extents.advance, strlen(ascii_printable)); - - return 0; -} - -void -wlloadfonts(char *fontstr, double fontsize) -{ - FcPattern *pattern; - double fontval; - float ceilf(float); - - if (fontstr[0] == '-') { - /* XXX: need XftXlfdParse equivalent */ - pattern = NULL; - } else { - pattern = FcNameParse((FcChar8 *)fontstr); - } - - if (!pattern) - die("st-wl: 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; - } - - FcConfigSubstitute(0, pattern, FcMatchPattern); - FcDefaultSubstitute(pattern); - - if (wlloadfont(&dc.font, pattern)) - die("st-wl: can't open font %s\n", fontstr); - - if (usedfontsize < 0) { - FcPatternGetDouble(dc.font.pattern, - FC_PIXEL_SIZE, 0, &fontval); - usedfontsize = fontval; - if (fontsize == 0) - defaultfontsize = fontval; - } - - /* Setting character width and height. */ - wl.cw = ceilf(dc.font.width * cwscale); - wl.ch = ceilf(dc.font.height * chscale); - - FcPatternDel(pattern, FC_SLANT); - FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ITALIC); - if (wlloadfont(&dc.ifont, pattern)) - die("st-wl: can't open font %s\n", fontstr); - - FcPatternDel(pattern, FC_WEIGHT); - FcPatternAddInteger(pattern, FC_WEIGHT, FC_WEIGHT_BOLD); - if (wlloadfont(&dc.ibfont, pattern)) - die("st-wl: can't open font %s\n", fontstr); - - FcPatternDel(pattern, FC_SLANT); - FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ROMAN); - if (wlloadfont(&dc.bfont, pattern)) - die("st-wl: can't open font %s\n", fontstr); - - FcPatternDestroy(pattern); -} - -void -wlunloadfont(Font *f) -{ - wld_font_close(f->match); - FcPatternDestroy(f->pattern); - if (f->set) - FcFontSetDestroy(f->set); -} - -void -wlunloadfonts(void) -{ - /* Free the loaded fonts in the font cache. */ - while (frclen > 0) - wld_font_close(frc[--frclen].font); - - wlunloadfont(&dc.font); - wlunloadfont(&dc.bfont); - wlunloadfont(&dc.ifont); - wlunloadfont(&dc.ibfont); -} - void wlzoom(const Arg *arg) { @@ -3364,456 +2591,22 @@ wlzoomreset(const Arg *arg) } void -wlinit(void) +redraw(void) { - struct wl_registry *registry; - - if (!(wl.dpy = wl_display_connect(NULL))) - die("Can't open display\n"); - - registry = wl_display_get_registry(wl.dpy); - wl_registry_add_listener(registry, ®listener, NULL); - wld.ctx = wld_wayland_create_context(wl.dpy, WLD_ANY); - wld.renderer = wld_create_renderer(wld.ctx); - - wl_display_roundtrip(wl.dpy); - - if (!wl.shm) - die("Display has no SHM\n"); - if (!wl.seat) - die("Display has no seat\n"); - if (!wl.datadevmanager) - die("Display has no data device manager\n"); - if (!wl.wm) - die("Display has no window manager\n"); - - wl.keyboard = wl_seat_get_keyboard(wl.seat); - wl_keyboard_add_listener(wl.keyboard, &kbdlistener, NULL); - wl.pointer = wl_seat_get_pointer(wl.seat); - wl_pointer_add_listener(wl.pointer, &ptrlistener, NULL); - wl.datadev = wl_data_device_manager_get_data_device(wl.datadevmanager, - wl.seat); - wl_data_device_add_listener(wl.datadev, &datadevlistener, NULL); - - /* font */ - if (!FcInit()) - die("Could not init fontconfig.\n"); - - usedfont = (opt_font == NULL)? font : opt_font; - wld.fontctx = wld_font_create_context(); - wlloadfonts(usedfont, 0); - - wlloadcols(); - wlloadcursor(); - - wl.vis = 0; - wl.h = 2 * borderpx + term.row * wl.ch; - wl.w = 2 * borderpx + term.col * wl.cw; - - wl.surface = wl_compositor_create_surface(wl.cmp); - wl_surface_add_listener(wl.surface, &surflistener, NULL); - - wl.xdgsurface = xdg_wm_base_get_xdg_surface(wl.wm, wl.surface); - xdg_surface_add_listener(wl.xdgsurface, &xdgsurflistener, NULL); - wl.xdgtoplevel = xdg_surface_get_toplevel(wl.xdgsurface); - xdg_toplevel_add_listener(wl.xdgtoplevel, &xdgtoplevellistener, NULL); - xdg_toplevel_set_app_id(wl.xdgtoplevel, opt_class ? opt_class : termname); - - wl_surface_commit(wl.surface); - - wl.xkb.ctx = xkb_context_new(0); - wlresettitle(); + tfulldirt(); } -/* - * TODO: Implement something like XftDrawGlyphFontSpec in wld, and then apply a - * similar patch to ae1923d27533ff46400d93765e971558201ca1ee - */ - void -wldraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) +draw(void) { - int winx = borderpx + x * wl.cw, winy = borderpx + y * wl.ch, - width = charlen * wl.cw, xp, i; - int frcflags, charexists; - int u8fl, u8fblen, u8cblen, doesexist; - char *u8c, *u8fs; - Rune unicodep; - Font *font = &dc.font; - FcResult fcres; - FcPattern *fcpattern, *fontpattern; - FcFontSet *fcsets[] = { NULL }; - FcCharSet *fccharset; - uint32_t fg, bg, temp; - int oneatatime; - - frcflags = FRC_NORMAL; - - /* 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; - font = &dc.ibfont; - frcflags = FRC_ITALICBOLD; - } else if (base.mode & ATTR_ITALIC) { - if (dc.ifont.badslant) - base.fg = defaultattr; - font = &dc.ifont; - frcflags = FRC_ITALIC; - } else if (base.mode & ATTR_BOLD) { - if (dc.bfont.badweight) - base.fg = defaultattr; - font = &dc.ifont; - frcflags = FRC_BOLD; - } - - if (IS_TRUECOL(base.fg)) { - fg = base.fg | 0xff000000; - } else { - fg = dc.col[base.fg]; - } + int y, y0; - if (IS_TRUECOL(base.bg)) { - bg = base.bg | 0xff000000; - } else { - bg = dc.col[base.bg]; - } - - if (base.mode & ATTR_BOLD) { - /* - * change basic system colors [0-7] - * to bright system colors [8-15] - */ - if (BETWEEN(base.fg, 0, 7) && !(base.mode & ATTR_FAINT)) - fg = dc.col[base.fg + 8]; - - if (base.mode & ATTR_ITALIC) { - font = &dc.ibfont; - frcflags = FRC_ITALICBOLD; - } else { - font = &dc.bfont; - frcflags = FRC_BOLD; - } - } - - if (IS_SET(MODE_REVERSE)) { - if (fg == dc.col[defaultfg]) { - fg = dc.col[defaultbg]; - } else { - fg = ~(fg & 0xffffff); - } - - if (bg == dc.col[defaultbg]) { - bg = dc.col[defaultfg]; - } else { - bg = ~(bg & 0xffffff); - } - } - - if (base.mode & ATTR_REVERSE) { - temp = fg; - fg = bg; - bg = temp; - } - - if (base.mode & ATTR_FAINT && !(base.mode & ATTR_BOLD)) { - fg = (fg & (0xff << 24)) - | ((((fg >> 16) & 0xff) / 2) << 16) - | ((((fg >> 8) & 0xff) / 2) << 8) - | ((fg & 0xff) / 2); - } - - 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) { - wlclear(0, (y == 0)? 0 : winy, borderpx, - ((y >= term.row-1)? wl.h : (winy + wl.ch))); - } - if (x + charlen >= term.col) { - wlclear(winx + width, (y == 0)? 0 : winy, wl.w, - ((y >= term.row-1)? wl.h : (winy + wl.ch))); - } - if (y == 0) - wlclear(winx, 0, winx + width, borderpx); - if (y == term.row-1) - wlclear(winx, winy + wl.ch, winx + width, wl.h); - - /* Clean up the region we want to draw to. */ - wld_fill_rectangle(wld.renderer, bg, winx, winy, width, wl.ch); - - for (xp = winx; bytelen > 0;) { - /* - * Search for the range in the to be printed string of glyphs - * that are in the main font. Then print that range. If - * some glyph is found that is not in the font, do the - * fallback dance. - */ - u8fs = s; - u8fblen = 0; - u8fl = 0; - oneatatime = font->width != wl.cw; - for (;;) { - u8c = s; - u8cblen = utf8decode(s, &unicodep, UTF_SIZ); - s += u8cblen; - bytelen -= u8cblen; - - doesexist = wld_font_ensure_char(font->match, unicodep); - if (doesexist) { - u8fl++; - u8fblen += u8cblen; - if (!oneatatime && bytelen > 0) - continue; - } - - if (u8fl > 0) { - wld_draw_text(wld.renderer, - font->match, fg, xp, - winy + font->ascent, - u8fs, u8fblen, NULL); - xp += wl.cw * u8fl; - } - break; - } - if (doesexist) { - if (oneatatime) - continue; - break; - } - - /* Search the font cache. */ - for (i = 0; i < frclen; i++) { - charexists = wld_font_ensure_char(frc[i].font, unicodep); - /* Everything correct. */ - if (charexists && frc[i].flags == frcflags) - break; - /* We got a default font for a not found glyph. */ - if (!charexists && frc[i].flags == frcflags \ - && frc[i].unicodep == unicodep) { - break; - } - } - - /* Nothing was found. */ - if (i >= 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, unicodep); - 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; - wld_font_close(frc[frclen].font); - frc[frclen].unicodep = 0; - } - - frc[frclen].font = wld_font_open_pattern(wld.fontctx, - fontpattern); - frc[frclen].flags = frcflags; - frc[frclen].unicodep = unicodep; - - i = frclen; - frclen++; - - FcPatternDestroy(fcpattern); - FcCharSetDestroy(fccharset); - } - - wld_draw_text(wld.renderer, frc[i].font, fg, - xp, winy + frc[i].font->ascent, - u8c, u8cblen, NULL); - - xp += wl.cw * wcwidth(unicodep); - } - - if (base.mode & ATTR_UNDERLINE) { - wld_fill_rectangle(wld.renderer, fg, winx, winy + font->ascent + 1, - width, 1); - } - - if (base.mode & ATTR_STRUCK) { - wld_fill_rectangle(wld.renderer, fg, winx, winy + 2 * font->ascent / 3, - width, 1); - } -} - -void -wldrawglyph(Glyph g, int x, int y) -{ - static char buf[UTF_SIZ]; - size_t len = utf8encode(g.u, buf); - int width = g.mode & ATTR_WIDE ? 2 : 1; - - wldraws(buf, g, x, y, width, len); -} - -void -wldrawcursor(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); - uint32_t 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; - wldrawglyph(og, oldx, oldy); - if (oldx != curx || oldy != term.c.y) { - wl_surface_damage(wl.surface, borderpx + oldx * wl.cw, - borderpx + oldy * wl.ch, wl.cw, wl.ch); - } - - 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 (wl.state & WIN_FOCUSED) { - switch (wl.cursor) { - case 7: /* st-wl 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; - wldrawglyph(g, term.c.x, term.c.y); - break; - case 3: /* Blinking Underline */ - case 4: /* Steady Underline */ - wld_fill_rectangle(wld.renderer, drawcol, - borderpx + curx * wl.cw, - borderpx + (term.c.y + 1) * wl.ch - \ - cursorthickness, - wl.cw, cursorthickness); - break; - case 5: /* Blinking bar */ - case 6: /* Steady bar */ - wld_fill_rectangle(wld.renderer, drawcol, - borderpx + curx * wl.cw, - borderpx + term.c.y * wl.ch, - cursorthickness, wl.ch); - break; - } - } else { - wld_fill_rectangle(wld.renderer, drawcol, - borderpx + curx * wl.cw, - borderpx + term.c.y * wl.ch, - wl.cw - 1, 1); - wld_fill_rectangle(wld.renderer, drawcol, - borderpx + curx * wl.cw, - borderpx + term.c.y * wl.ch, - 1, wl.ch - 1); - wld_fill_rectangle(wld.renderer, drawcol, - borderpx + (curx + 1) * wl.cw - 1, - borderpx + term.c.y * wl.ch, - 1, wl.ch - 1); - wld_fill_rectangle(wld.renderer, drawcol, - borderpx + curx * wl.cw, - borderpx + (term.c.y + 1) * wl.ch - 1, - wl.cw, 1); - } - wl_surface_damage(wl.surface, borderpx + curx * wl.cw, - borderpx + term.c.y * wl.ch, wl.cw, wl.ch); - oldx = curx, oldy = term.c.y; -} - -void -wlsettitle(char *title) -{ - xdg_toplevel_set_title(wl.xdgtoplevel, title); -} - -void -wlresettitle(void) -{ - wlsettitle(opt_title ? opt_title : "st-wl"); -} - -void -redraw(void) -{ - tfulldirt(); -} - -void -draw(void) -{ - int y, y0; - - for (y = 0; y <= term.bot; ++y) { - if (!term.dirty[y]) - continue; - for (y0 = y; y <= term.bot && term.dirty[y]; ++y); - wl_surface_damage(wl.surface, 0, borderpx + y0 * wl.ch, - wl.w, (y - y0) * wl.ch); + for (y = 0; y <= term.bot; ++y) { + if (!term.dirty[y]) + continue; + for (y0 = y; y <= term.bot && term.dirty[y]; ++y); + wl_surface_damage(wl.surface, 0, borderpx + y0 * wl.ch, + wl.w, (y - y0) * wl.ch); } wld_set_target_buffer(wld.renderer, wld.buffer); @@ -3878,58 +2671,12 @@ wlseturgency(int add) /* XXX: no urgency equivalent yet in wayland */ } -int -match(uint mask, uint state) -{ - return mask == MOD_MASK_ANY || mask == (state & ~(ignoremod)); -} - void numlock(const Arg *dummy) { term.numlock ^= 1; } -char* -kmap(xkb_keysym_t 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 (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 cresize(int width, int height) { @@ -3947,388 +2694,6 @@ cresize(int width, int height) wlresize(col, row); } -void -regglobal(void *data, struct wl_registry *registry, uint32_t name, - const char *interface, uint32_t version) -{ - if (strcmp(interface, "wl_compositor") == 0) { - wl.cmp = wl_registry_bind(registry, name, &wl_compositor_interface, 3); - } else if (strcmp(interface, "xdg_wm_base") == 0) { - wl.wm = wl_registry_bind(registry, name, &xdg_wm_base_interface, 1); - xdg_wm_base_add_listener(wl.wm, &wmlistener, NULL); - } else if (strcmp(interface, "wl_shm") == 0) { - wl.shm = wl_registry_bind(registry, name, &wl_shm_interface, 1); - } else if (strcmp(interface, "wl_seat") == 0) { - wl.seat = wl_registry_bind(registry, name, &wl_seat_interface, 4); - } else if (strcmp(interface, "wl_data_device_manager") == 0) { - wl.datadevmanager = wl_registry_bind(registry, name, - &wl_data_device_manager_interface, 1); - } else if (strcmp(interface, "wl_output") == 0) { - /* bind to outputs so we can get surface enter events */ - wl_registry_bind(registry, name, &wl_output_interface, 2); - } -} - -void -regglobalremove(void *data, struct wl_registry *registry, uint32_t name) -{ -} - -void -surfenter(void *data, struct wl_surface *surface, struct wl_output *output) -{ - wl.vis++; - if (!(wl.state & WIN_VISIBLE)) - wl.state |= WIN_VISIBLE; -} - -void -surfleave(void *data, struct wl_surface *surface, struct wl_output *output) -{ - if (--wl.vis == 0) - wl.state &= ~WIN_VISIBLE; -} - -void -framedone(void *data, struct wl_callback *callback, uint32_t msecs) -{ - wl_callback_destroy(callback); - wl.framecb = NULL; - if (needdraw && wl.state & WIN_VISIBLE) { - draw(); - } -} - -void -kbdkeymap(void *data, struct wl_keyboard *keyboard, uint32_t format, int32_t fd, - uint32_t size) -{ - char *string; - - if (format != WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1) { - close(fd); - return; - } - - string = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0); - - if (string == MAP_FAILED) { - close(fd); - return; - } - - wl.xkb.keymap = xkb_keymap_new_from_string(wl.xkb.ctx, string, - XKB_KEYMAP_FORMAT_TEXT_V1, 0); - munmap(string, size); - close(fd); - wl.xkb.state = xkb_state_new(wl.xkb.keymap); - - wl.xkb.ctrl = xkb_keymap_mod_get_index(wl.xkb.keymap, XKB_MOD_NAME_CTRL); - wl.xkb.alt = xkb_keymap_mod_get_index(wl.xkb.keymap, XKB_MOD_NAME_ALT); - wl.xkb.shift = xkb_keymap_mod_get_index(wl.xkb.keymap, XKB_MOD_NAME_SHIFT); - wl.xkb.logo = xkb_keymap_mod_get_index(wl.xkb.keymap, XKB_MOD_NAME_LOGO); - - wl.xkb.mods = 0; -} - -void -kbdenter(void *data, struct wl_keyboard *keyboard, uint32_t serial, - struct wl_surface *surface, struct wl_array *keys) -{ - wl.state |= WIN_FOCUSED; - if (IS_SET(MODE_FOCUS)) - ttywrite("\033[I", 3); - /* need to redraw the cursor */ - needdraw = true; -} - -void -kbdleave(void *data, struct wl_keyboard *keyboard, uint32_t serial, - struct wl_surface *surface) -{ - /* selection offers are invalidated when we lose keyboard focus */ - wl.seloffer = NULL; - wl.state &= ~WIN_FOCUSED; - if (IS_SET(MODE_FOCUS)) - ttywrite("\033[O", 3); - /* need to redraw the cursor */ - needdraw = true; - /* disable key repeat */ - repeat.len = 0; -} - -void -kbdkey(void *data, struct wl_keyboard *keyboard, uint32_t serial, uint32_t time, - uint32_t key, uint32_t state) -{ - xkb_keysym_t ksym; - char buf[32], *str; - int len; - Rune c; - Shortcut *bp; - - if (IS_SET(MODE_KBDLOCK)) - return; - - if (state == WL_KEYBOARD_KEY_STATE_RELEASED) { - if (repeat.key == key) - repeat.len = 0; - return; - } - - ksym = xkb_state_key_get_one_sym(wl.xkb.state, key + 8); - len = xkb_keysym_to_utf8(ksym, buf, sizeof buf); - if (len > 0) - --len; - - /* 1. shortcuts */ - for (bp = shortcuts; bp < shortcuts + LEN(shortcuts); bp++) { - if (ksym == bp->keysym && match(bp->mod, wl.xkb.mods)) { - bp->func(&(bp->arg)); - return; - } - } - - /* 2. custom keys from config.h */ - if ((str = kmap(ksym, wl.xkb.mods))) { - len = strlen(str); - goto send; - } - - /* 3. composed string from input method */ - if (len == 0) - return; - if (len == 1 && wl.xkb.mods & MOD_MASK_ALT) { - 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; - } - } - /* convert character to control character */ - else if (len == 1 && wl.xkb.mods & MOD_MASK_CTRL) { - if ((*buf >= '@' && *buf < '\177') || *buf == ' ') - *buf &= 0x1F; - else if (*buf == '2') *buf = '\000'; - else if (*buf >= '3' && *buf <= '7') - *buf -= ('3' - '\033'); - else if (*buf == '8') *buf = '\177'; - else if (*buf == '/') *buf = '_' & 0x1F; - } - - str = buf; - -send: - memcpy(repeat.str, str, len); - repeat.key = key; - repeat.len = len; - repeat.started = false; - clock_gettime(CLOCK_MONOTONIC, &repeat.last); - ttysend(str, len); -} - -void -kbdmodifiers(void *data, struct wl_keyboard *keyboard, uint32_t serial, - uint32_t dep, uint32_t lat, uint32_t lck, uint32_t group) -{ - xkb_mod_mask_t mod_mask; - - xkb_state_update_mask(wl.xkb.state, dep, lat, lck, group, 0, 0); - - mod_mask = xkb_state_serialize_mods(wl.xkb.state, XKB_STATE_MODS_EFFECTIVE); - wl.xkb.mods = 0; - - if (mod_mask & (1 << wl.xkb.ctrl)) - wl.xkb.mods |= MOD_MASK_CTRL; - if (mod_mask & (1 << wl.xkb.alt)) - wl.xkb.mods |= MOD_MASK_ALT; - if (mod_mask & (1 << wl.xkb.shift)) - wl.xkb.mods |= MOD_MASK_SHIFT; - if (mod_mask & (1 << wl.xkb.logo)) - wl.xkb.mods |= MOD_MASK_LOGO; -} - -void -kbdrepeatinfo(void *data, struct wl_keyboard *keyboard, int32_t rate, - int32_t delay) -{ - keyrepeatdelay = delay; - keyrepeatinterval = 1000 / rate; -} - -void -ptrenter(void *data, struct wl_pointer *pointer, uint32_t serial, - struct wl_surface *surface, wl_fixed_t x, wl_fixed_t y) -{ - struct wl_cursor_image *img = cursor.cursor->images[0]; - struct wl_buffer *buffer; - - wl_pointer_set_cursor(pointer, serial, cursor.surface, - img->hotspot_x, img->hotspot_y); - buffer = wl_cursor_image_get_buffer(img); - wl_surface_attach(cursor.surface, buffer, 0, 0); - wl_surface_damage(cursor.surface, 0, 0, img->width, img->height); - wl_surface_commit(cursor.surface); -} - -void -ptrleave(void *data, struct wl_pointer *pointer, uint32_t serial, - struct wl_surface *surface) -{ -} - -void -ptrmotion(void *data, struct wl_pointer * pointer, uint32_t serial, - wl_fixed_t x, wl_fixed_t y) -{ - int oldey, oldex, oldsby, oldsey; - - if (IS_SET(MODE_MOUSE)) { - wlmousereportmotion(x, y); - return; - } - - wl.px = wl_fixed_to_int(x); - wl.py = wl_fixed_to_int(y); - - 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(); - - if (oldey != sel.oe.y || oldex != sel.oe.x) - tsetdirt(MIN(sel.nb.y, oldsby), MAX(sel.ne.y, oldsey)); -} - -void -ptrbutton(void * data, struct wl_pointer * pointer, uint32_t serial, - uint32_t time, uint32_t button, uint32_t state) -{ - MouseShortcut *ms; - - if (IS_SET(MODE_MOUSE) && !(wl.xkb.mods & forceselmod)) { - wlmousereportbutton(button, state); - return; - } - - switch (state) { - case WL_POINTER_BUTTON_STATE_RELEASED: - if (button == BTN_MIDDLE) { - selpaste(NULL); - } else if (button == BTN_LEFT) { - if (sel.mode == SEL_READY) { - getbuttoninfo(); - selcopy(serial); - } else - selclear(); - sel.mode = SEL_IDLE; - tsetdirt(sel.nb.y, sel.ne.y); - } - break; - - case WL_POINTER_BUTTON_STATE_PRESSED: - for (ms = mshortcuts; ms < mshortcuts + LEN(mshortcuts); ms++) { - if (button == ms->b && match(ms->mask, wl.xkb.mods)) { - ttysend(ms->s, strlen(ms->s)); - return; - } - } - - if (button == BTN_LEFT) { - /* Clear previous selection, logically and visually. */ - selclear(); - sel.mode = SEL_EMPTY; - sel.type = SEL_REGULAR; - sel.oe.x = sel.ob.x = x2col(wl.px); - sel.oe.y = sel.ob.y = y2row(wl.py); - - /* - * If the user clicks below predefined timeouts - * specific snapping behaviour is exposed. - */ - if (time - sel.tclick2 <= tripleclicktimeout) { - sel.snap = SNAP_LINE; - } else if (time - 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 = time; - } - break; - } -} - -void -ptraxis(void * data, struct wl_pointer * pointer, uint32_t time, uint32_t axis, - wl_fixed_t value) -{ - Axiskey *ak; - int dir = value > 0 ? +1 : -1; - - if (IS_SET(MODE_MOUSE) && !(wl.xkb.mods & forceselmod)) { - wlmousereportaxis(axis, value); - return; - } - - for (ak = ashortcuts; ak < ashortcuts + LEN(ashortcuts); ak++) { - if (axis == ak->axis && dir == ak->dir - && match(ak->mask, wl.xkb.mods)) { - ttysend(ak->s, strlen(ak->s)); - return; - } - } -} - -void -wmping(void *data, struct xdg_wm_base *wm, uint32_t serial) -{ - xdg_wm_base_pong(wm, serial); -} - -void -xdgsurfconfigure(void *data, struct xdg_surface *surf, uint32_t serial) -{ - xdg_surface_ack_configure(surf, serial); -} - -void -xdgtoplevelconfigure(void *data, struct xdg_toplevel *toplevel, - int32_t w, int32_t h, struct wl_array *states) -{ - if (w == wl.w && h == wl.h) - return; - cresize(w, h); - if (wl.configured) - ttyresize(); - else - wl.configured = true; -} - -void -xdgtoplevelclose(void *data, struct xdg_toplevel *toplevel) -{ - /* Send SIGHUP to shell */ - kill(pid, SIGHUP); - exit(0); -} - void datadevoffer(void *data, struct wl_data_device *datadev, struct wl_data_offer *offer) @@ -4406,96 +2771,6 @@ datasrccancelled(void *data, struct wl_data_source *source) wl_data_source_destroy(source); } -void -run(void) -{ - fd_set rfd; - int wlfd = wl_display_get_fd(wl.dpy), blinkset = 0; - struct timespec drawtimeout, *tv = NULL, now, last, lastblink; - ulong msecs; - - /* Look for initial configure. */ - wl_display_roundtrip(wl.dpy); - if (!wl.configured) - cresize(wl.w, wl.h); - ttynew(); - ttyresize(); - draw(); - - clock_gettime(CLOCK_MONOTONIC, &last); - lastblink = last; - - for (;;) { - FD_ZERO(&rfd); - FD_SET(cmdfd, &rfd); - FD_SET(wlfd, &rfd); - - if (pselect(MAX(wlfd, 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(wlfd, &rfd)) { - if (wl_display_dispatch(wl.dpy) == -1) - die("Connection error\n"); - } - - clock_gettime(CLOCK_MONOTONIC, &now); - msecs = -1; - - if (blinkset && blinktimeout) { - if (TIMEDIFF(now, lastblink) >= blinktimeout) { - tsetdirtattr(ATTR_BLINK); - term.mode ^= MODE_BLINK; - lastblink = now; - } else { - msecs = MIN(msecs, blinktimeout - \ - TIMEDIFF(now, lastblink)); - } - } - if (repeat.len > 0) { - if (TIMEDIFF(now, repeat.last) >= \ - (repeat.started ? keyrepeatinterval : \ - keyrepeatdelay)) { - repeat.started = true; - repeat.last = now; - ttysend(repeat.str, repeat.len); - } else { - msecs = MIN(msecs, (repeat.started ? \ - keyrepeatinterval : keyrepeatdelay) - \ - TIMEDIFF(now, repeat.last)); - } - } - - if (needdraw && wl.state & WIN_VISIBLE) { - if (!wl.framecb) { - draw(); - } - } - - if (msecs == -1) { - tv = NULL; - } else { - drawtimeout.tv_nsec = 1E6 * msecs; - drawtimeout.tv_sec = 0; - tv = &drawtimeout; - } - - wl_display_dispatch_pending(wl.dpy); - wl_display_flush(wl.dpy); - } -} - void usage(void) { @@ -4508,62 +2783,3 @@ usage(void) " [-T title] [-t title] [-w windowid] -l line" " [stty_args ...]\n", argv0, argv0); } - -int -main(int argc, char *argv[]) -{ - wl.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 '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-wl 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, ""); - tnew(MAX(cols, 1), MAX(rows, 1)); - wlinit(); - selinit(); - run(); - - return 0; -} - diff --git a/st-wl.h b/st-wl.h new file mode 100644 index 0000000..4bf9d13 --- /dev/null +++ b/st-wl.h @@ -0,0 +1,387 @@ + +/* Arbitrary sizes */ +#define UTF_SIZ 4 +#define ESC_BUF_SIZ (128*UTF_SIZ) + +#define MOD_MASK_ANY UINT_MAX +#define MOD_MASK_NONE 0 +#define MOD_MASK_CTRL (1<<0) +#define MOD_MASK_ALT (1<<1) +#define MOD_MASK_SHIFT (1<<2) +#define MOD_MASK_LOGO (1<<3) + +#define AXIS_VERTICAL WL_POINTER_AXIS_VERTICAL_SCROLL + + + +/* Macros */ +#define LEN(a) (sizeof(a) / sizeof(a)[0]) +#define BETWEEN(x, a, b) ((a) <= (x) && (x) <= (b)) +#define MAX(a, b) ((a) < (b) ? (b) : (a)) +#define MIN(a, b) ((a) < (b) ? (a) : (b)) +#define MODBIT(x, set, bit) ((set) ? ((x) |= (bit)) : ((x) &= ~(bit))) +#define LIMIT(x, a, b) (x) = (x) < (a) ? (a) : (x) > (b) ? (b) : (x) +#define IS_SET(flag) ((term.mode & (flag)) != 0) + + + +/* type declarations */ +typedef unsigned char uchar; +typedef unsigned int uint; +typedef unsigned long ulong; +typedef unsigned short ushort; + +typedef uint_least32_t Rune; + +typedef struct { + xkb_keysym_t 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; + +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; + int y; + char state; +} TCursor; + +typedef union { + int i; + uint ui; + float f; + const void *v; +} Arg; + +typedef struct { + uint mod; + xkb_keysym_t keysym; + void (*func)(const Arg *); + const Arg arg; +} Shortcut; + +/* 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 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 numlock; /* lock numbers in keyboard */ + int *tabs; +} Term; + +typedef struct { + struct xkb_context *ctx; + struct xkb_keymap *keymap; + struct xkb_state *state; + xkb_mod_index_t ctrl, alt, shift, logo; + unsigned int mods; +} XKB; + +typedef struct { + uint b; + uint mask; + char *s; +} MouseShortcut; + +typedef struct { + int axis; + int dir; + uint mask; + char s[ESC_BUF_SIZ]; +} Axiskey; + +typedef struct { + struct wl_display *dpy; + struct wl_compositor *cmp; + struct wl_shm *shm; + struct wl_seat *seat; + struct wl_keyboard *keyboard; + struct wl_pointer *pointer; + struct wl_data_device_manager *datadevmanager; + struct wl_data_device *datadev; + struct wl_data_offer *seloffer; + struct wl_surface *surface; + struct wl_buffer *buffer; + struct xdg_wm_base *wm; + struct xdg_surface *xdgsurface; + struct xdg_toplevel *xdgtoplevel; + XKB xkb; + bool configured; + int px, py; /* pointer x and y */ + int tw, th; /* tty width and height */ + int w, h; /* window width and height */ + int ch; /* char height */ + int cw; /* char width */ + int vis; + char state; /* focus, redraw, visible */ + int cursor; /* cursor style */ + struct wl_callback * framecb; +} Wayland; + +typedef struct { + char str[32]; + uint32_t key; + int len; + bool started; + struct timespec last; +} Repeat; + +typedef struct { + struct wld_context *ctx; + struct wld_font_context *fontctx; + struct wld_renderer *renderer; + struct wld_buffer *buffer, *oldbuffer; +} WLD; + +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; + struct wl_data_source *source; + int alt; + uint32_t tclick1, tclick2; +} Selection; + + + + +/* function declarations */ +void *xmalloc(size_t); + +size_t utf8decode(char *, Rune *, size_t); +size_t utf8encode(Rune, char *); +void usage(void); +void cresize(int, int); +void ttynew(void); +void ttysend(char *, size_t); +size_t ttyread(void); +void ttywrite(const char *, size_t); +void ttyresize(void); +void draw(void); +int cmdfd; +void die(const char *, ...); + +int tattrset(int); +void tsetdirtattr(int); +void tsetdirt(int, int); + +char *xstrdup(char *); +void tnew(int, int); + +void selinit(void); +void selnormalize(void); +void selclear(void); +void selcopy(uint32_t); +int selected(int, int); + +void wlsettitle(char *); +void wlresettitle(void); +void wlinit(void); +void wlresize(int, int); +void wlloadcols(void); +int wlsetcolorname(int, const char *); +void wlloadfonts(char *, double); +void wlunloadfonts(void); +void wldrawcursor(void); +void wldraws(char *, Glyph, int, int, int, int); +void framedone(void *, struct wl_callback *, uint32_t); + +void datadevoffer(void *, struct wl_data_device *, + struct wl_data_offer *); +void datadeventer(void *, struct wl_data_device *, uint32_t, + struct wl_surface *, wl_fixed_t, wl_fixed_t, struct wl_data_offer *); +void datadevleave(void *, struct wl_data_device *); +void datadevmotion(void *, struct wl_data_device *, uint32_t, + wl_fixed_t x, wl_fixed_t y); +void datadevdrop(void *, struct wl_data_device *); +void datadevselection(void *, struct wl_data_device *, + struct wl_data_offer *); +void dataofferoffer(void *, struct wl_data_offer *, const char *); +void datasrctarget(void *, struct wl_data_source *, const char *); +void datasrcsend(void *, struct wl_data_source *, const char *, int32_t); +void datasrccancelled(void *, struct wl_data_source *); + + + +/* global variables */ +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 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 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 +}; + +enum window_state { + WIN_VISIBLE = 1, + WIN_FOCUSED = 2 +}; + +pid_t pid; +WLD wld; +Wayland wl; +Term term; +Repeat repeat; +Selection sel; + +bool needdraw; + +char **opt_cmd; +char *opt_class; +char *opt_embed; +char *opt_font; +char *opt_io; +char *opt_line; +char *opt_name; +char *opt_title; + +char *usedfont; +double usedfontsize; +double defaultfontsize; + + + +/* config.h globals */ +extern char font[]; +extern int borderpx; +extern float cwscale; +extern float chscale; +extern unsigned int doubleclicktimeout; +extern unsigned int tripleclicktimeout; +extern unsigned int keyrepeatdelay; +extern unsigned int keyrepeatinterval; +extern int allowaltscreen; +extern unsigned int xfps; +extern unsigned int actionfps; +extern unsigned int cursorthickness; +extern unsigned int blinktimeout; +extern char termname[]; +extern unsigned int tabsspaces; +extern const char *colorname[]; +extern size_t colornamelen; +extern size_t maxcolornamelen; +extern unsigned int defaultfg; +extern unsigned int defaultbg; +extern unsigned int defaultcs; +extern unsigned int defaultrcs; +extern unsigned int cursorshape; +extern unsigned int cols; +extern unsigned int rows; +extern char mouseshape[]; +extern unsigned int mousefg; +extern unsigned int mousebg; +extern unsigned int defaultattr; +extern MouseShortcut mshortcuts[]; +extern Axiskey ashortcuts[]; +extern size_t ashortcutslen; +extern size_t mshortcutslen; +extern Shortcut shortcuts[]; +extern size_t shortcutslen; +extern xkb_keysym_t mappedkeys[]; +extern size_t mappedkeyslen; +extern uint forceselmod; +extern uint selmasks[]; +extern size_t selmaskslen; +extern char ascii_printable[]; +extern uint ignoremod; +extern Key key[]; +extern size_t keylen; + +/* function definitions used in config.h */ +void numlock(const Arg *); +void selpaste(const Arg *); +void wlzoom(const Arg *); +void wlzoomabs(const Arg *); +void wlzoomreset(const Arg *); +void printsel(const Arg *); +void printscreen(const Arg *); +void iso14755(const Arg *); +void toggleprinter(const Arg *); +void sendbreak(const Arg *); diff --git a/wl.c b/wl.c new file mode 100644 index 0000000..658eb3a --- /dev/null +++ b/wl.c @@ -0,0 +1,1581 @@ +/* See LICENSE for license details. */ +#include +#include +#include +#include +/* for BTN_* definitions */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "arg.h" +#include "st-wl.h" +#include "xdg-shell-client-protocol.h" + + + +/* Macros */ + +#define DIVCEIL(n, d) (((n) + ((d) - 1)) / (d)) +#define TIMEDIFF(t1, t2) ((t1.tv_sec-t2.tv_sec)*1000 + \ + (t1.tv_nsec-t2.tv_nsec)/1E6) +#define IS_TRUECOL(x) (1 << 24 & (x)) + + + +/* Type declarations */ + +/* Font structure */ +typedef struct { + int height; + int width; + int ascent; + int descent; + int badslant; + int badweight; + short lbearing; + short rbearing; + struct wld_font *match; + FcFontSet *set; + FcPattern *pattern; +} Font; + +/* Drawing Context */ +typedef struct { + uint32_t *col; + size_t collen; + Font font, bfont, ifont, ibfont; +} DC; + +typedef struct { + struct wl_cursor_theme *theme; + struct wl_cursor *cursor; + struct wl_surface *surface; +} Cursor; + + + +/* Function declarations */ +static void run(void); +static inline int match(uint, uint); + +static void kbdkeymap(void *, struct wl_keyboard *, uint32_t, int32_t, uint32_t); +static void kbdenter(void *, struct wl_keyboard *, uint32_t, + struct wl_surface *, struct wl_array *); +static void kbdleave(void *, struct wl_keyboard *, uint32_t, + struct wl_surface *); +static void kbdkey(void *, struct wl_keyboard *, uint32_t, uint32_t, uint32_t, + uint32_t); +static void kbdmodifiers(void *, struct wl_keyboard *, uint32_t, uint32_t, + uint32_t, uint32_t, uint32_t); +static void kbdrepeatinfo(void *, struct wl_keyboard *, int32_t, int32_t); + +static int x2col(int); +static int y2row(int); +static void ptrenter(void *, struct wl_pointer *, uint32_t, struct wl_surface *, + wl_fixed_t, wl_fixed_t); +static void ptrleave(void *, struct wl_pointer *, uint32_t, + struct wl_surface *); +static void ptrmotion(void *, struct wl_pointer *, uint32_t, + wl_fixed_t, wl_fixed_t); +static void ptrbutton(void *, struct wl_pointer *, uint32_t, uint32_t, + uint32_t, uint32_t); +static void ptraxis(void *, struct wl_pointer *, uint32_t, uint32_t, + wl_fixed_t); +static void wlloadcursor(void); + +static inline uchar sixd_to_8bit(int); +static int wlloadfont(Font *, FcPattern *); +static void wlunloadfont(Font *f); +static void wldrawglyph(Glyph, int, int); +static void wlclear(int, int, int, int); + +static void regglobal(void *, struct wl_registry *, uint32_t, const char *, + uint32_t); +static void regglobalremove(void *, struct wl_registry *, uint32_t); +static void surfenter(void *, struct wl_surface *, struct wl_output *); +static void surfleave(void *, struct wl_surface *, struct wl_output *); +static void wmping(void *, struct xdg_wm_base *, uint32_t); +static void xdgsurfconfigure(void *, struct xdg_surface *, uint32_t); +static void xdgtoplevelconfigure(void *, struct xdg_toplevel *, + int32_t, int32_t, struct wl_array *); +static void xdgtoplevelclose(void *, struct xdg_toplevel *); + + + +/* Globals */ +static struct wl_registry_listener reglistener = { regglobal, regglobalremove }; +static struct wl_surface_listener surflistener = { surfenter, surfleave }; +static struct wl_keyboard_listener kbdlistener = + { kbdkeymap, kbdenter, kbdleave, kbdkey, kbdmodifiers, kbdrepeatinfo }; +static struct wl_pointer_listener ptrlistener = + { ptrenter, ptrleave, ptrmotion, ptrbutton, ptraxis }; +static struct xdg_wm_base_listener wmlistener = { wmping }; +static struct xdg_surface_listener xdgsurflistener = { xdgsurfconfigure }; +static struct xdg_toplevel_listener xdgtoplevellistener = + { xdgtoplevelconfigure, xdgtoplevelclose }; +static struct wl_data_device_listener datadevlistener = + { datadevoffer, datadeventer, datadevleave, datadevmotion, datadevdrop, + datadevselection }; + +static DC dc; +static Cursor cursor; +static int oldbutton = 3; /* button event on startup: 3 = release */ +static int oldx, oldy; + + +/* Font Ring Cache */ +enum { + FRC_NORMAL, + FRC_ITALIC, + FRC_BOLD, + FRC_ITALICBOLD +}; + +typedef struct { + struct wld_font *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; + + + +/* Keyboard stuff */ +void +kbdkeymap(void *data, struct wl_keyboard *keyboard, uint32_t format, int32_t fd, + uint32_t size) +{ + char *string; + + if (format != WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1) { + close(fd); + return; + } + + string = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0); + + if (string == MAP_FAILED) { + close(fd); + return; + } + + wl.xkb.keymap = xkb_keymap_new_from_string(wl.xkb.ctx, string, + XKB_KEYMAP_FORMAT_TEXT_V1, 0); + munmap(string, size); + close(fd); + wl.xkb.state = xkb_state_new(wl.xkb.keymap); + + wl.xkb.ctrl = xkb_keymap_mod_get_index(wl.xkb.keymap, XKB_MOD_NAME_CTRL); + wl.xkb.alt = xkb_keymap_mod_get_index(wl.xkb.keymap, XKB_MOD_NAME_ALT); + wl.xkb.shift = xkb_keymap_mod_get_index(wl.xkb.keymap, XKB_MOD_NAME_SHIFT); + wl.xkb.logo = xkb_keymap_mod_get_index(wl.xkb.keymap, XKB_MOD_NAME_LOGO); + + wl.xkb.mods = 0; +} + +void +kbdenter(void *data, struct wl_keyboard *keyboard, uint32_t serial, + struct wl_surface *surface, struct wl_array *keys) +{ + wl.state |= WIN_FOCUSED; + if (IS_SET(MODE_FOCUS)) + ttywrite("\033[I", 3); + /* need to redraw the cursor */ + needdraw = true; +} + +void +kbdleave(void *data, struct wl_keyboard *keyboard, uint32_t serial, + struct wl_surface *surface) +{ + /* selection offers are invalidated when we lose keyboard focus */ + wl.seloffer = NULL; + wl.state &= ~WIN_FOCUSED; + if (IS_SET(MODE_FOCUS)) + ttywrite("\033[O", 3); + /* need to redraw the cursor */ + needdraw = true; + /* disable key repeat */ + repeat.len = 0; +} + +int +match(uint mask, uint state) +{ + return mask == MOD_MASK_ANY || mask == (state & ~(ignoremod)); +} + +char* +kmap(xkb_keysym_t k, uint state) +{ + Key *kp; + int i; + + /* Check for mapped keys out of X11 function keys. */ + for (i = 0; i < mappedkeyslen; i++) { + if (mappedkeys[i] == k) + break; + } + if (i == mappedkeyslen) { + if ((k & 0xFFFF) < 0xFD00) + return NULL; + } + + for (kp = key; kp < key + keylen; 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 +kbdkey(void *data, struct wl_keyboard *keyboard, uint32_t serial, uint32_t time, + uint32_t key, uint32_t state) +{ + xkb_keysym_t ksym; + char buf[32], *str; + int len; + Rune c; + Shortcut *bp; + + if (IS_SET(MODE_KBDLOCK)) + return; + + if (state == WL_KEYBOARD_KEY_STATE_RELEASED) { + if (repeat.key == key) + repeat.len = 0; + return; + } + + ksym = xkb_state_key_get_one_sym(wl.xkb.state, key + 8); + len = xkb_keysym_to_utf8(ksym, buf, sizeof buf); + if (len > 0) + --len; + + /* 1. shortcuts */ + for (bp = shortcuts; bp < shortcuts + shortcutslen; bp++) { + if (ksym == bp->keysym && match(bp->mod, wl.xkb.mods)) { + bp->func(&(bp->arg)); + return; + } + } + + /* 2. custom keys from config.h */ + if ((str = kmap(ksym, wl.xkb.mods))) { + len = strlen(str); + goto send; + } + + /* 3. composed string from input method */ + if (len == 0) + return; + if (len == 1 && wl.xkb.mods & MOD_MASK_ALT) { + 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; + } + } + /* convert character to control character */ + else if (len == 1 && wl.xkb.mods & MOD_MASK_CTRL) { + if ((*buf >= '@' && *buf < '\177') || *buf == ' ') + *buf &= 0x1F; + else if (*buf == '2') *buf = '\000'; + else if (*buf >= '3' && *buf <= '7') + *buf -= ('3' - '\033'); + else if (*buf == '8') *buf = '\177'; + else if (*buf == '/') *buf = '_' & 0x1F; + } + + str = buf; + +send: + memcpy(repeat.str, str, len); + repeat.key = key; + repeat.len = len; + repeat.started = false; + clock_gettime(CLOCK_MONOTONIC, &repeat.last); + ttysend(str, len); +} + +void +kbdmodifiers(void *data, struct wl_keyboard *keyboard, uint32_t serial, + uint32_t dep, uint32_t lat, uint32_t lck, uint32_t group) +{ + xkb_mod_mask_t mod_mask; + + xkb_state_update_mask(wl.xkb.state, dep, lat, lck, group, 0, 0); + + mod_mask = xkb_state_serialize_mods(wl.xkb.state, XKB_STATE_MODS_EFFECTIVE); + wl.xkb.mods = 0; + + if (mod_mask & (1 << wl.xkb.ctrl)) + wl.xkb.mods |= MOD_MASK_CTRL; + if (mod_mask & (1 << wl.xkb.alt)) + wl.xkb.mods |= MOD_MASK_ALT; + if (mod_mask & (1 << wl.xkb.shift)) + wl.xkb.mods |= MOD_MASK_SHIFT; + if (mod_mask & (1 << wl.xkb.logo)) + wl.xkb.mods |= MOD_MASK_LOGO; +} + +void +kbdrepeatinfo(void *data, struct wl_keyboard *keyboard, int32_t rate, + int32_t delay) +{ + keyrepeatdelay = delay; + keyrepeatinterval = 1000 / rate; +} + + + +/* Mouse stuff */ +int +x2col(int x) +{ + x -= borderpx; + x /= wl.cw; + + return LIMIT(x, 0, term.col-1); +} + +int +y2row(int y) +{ + y -= borderpx; + y /= wl.ch; + + return LIMIT(y, 0, term.row-1); +} + +void +getbuttoninfo(void) +{ + int type; + uint state = wl.xkb.mods & ~forceselmod; + + sel.alt = IS_SET(MODE_ALTSCREEN); + + sel.oe.x = x2col(wl.px); + sel.oe.y = y2row(wl.py); + selnormalize(); + + sel.type = SEL_REGULAR; + for (type = 1; type < selmaskslen; ++type) { + if (match(selmasks[type], state)) { + sel.type = type; + break; + } + } +} + +void +wlmousereport(int button, bool release, int x, int y) +{ + int len; + char buf[40]; + + if (!IS_SET(MODE_MOUSEX10)) { + button += ((wl.xkb.mods & MOD_MASK_SHIFT) ? 4 : 0) + + ((wl.xkb.mods & MOD_MASK_LOGO ) ? 8 : 0) + + ((wl.xkb.mods & MOD_MASK_CTRL ) ? 16 : 0); + } + + if (IS_SET(MODE_MOUSESGR)) { + len = snprintf(buf, sizeof(buf), "\033[<%d;%d;%d%c", + button, x+1, y+1, release ? '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 +wlmousereportbutton(uint32_t button, uint32_t state) +{ + bool release = state == WL_POINTER_BUTTON_STATE_RELEASED; + + if (!IS_SET(MODE_MOUSESGR) && release) { + button = 3; + } else { + switch (button) { + case BTN_LEFT: + button = 0; + break; + case BTN_MIDDLE: + button = 1; + break; + case BTN_RIGHT: + button = 2; + break; + } + } + + oldbutton = release ? 3 : button; + + /* don't report release events when in X10 mode */ + if (IS_SET(MODE_MOUSEX10) && release) { + return; + } + + wlmousereport(button, release, oldx, oldy); +} + +void +wlmousereportmotion(wl_fixed_t fx, wl_fixed_t fy) +{ + int x = x2col(wl_fixed_to_int(fx)), y = y2row(wl_fixed_to_int(fy)); + + if (x == oldx && y == oldy) + 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; + + oldx = x; + oldy = y; + wlmousereport(oldbutton + 32, false, x, y); +} + +void +wlmousereportaxis(uint32_t axis, wl_fixed_t amount) +{ + wlmousereport(64 + (axis == AXIS_VERTICAL ? 4 : 6) + + (amount > 0 ? 1 : 0), false, oldx, oldy); +} + +void +ptrenter(void *data, struct wl_pointer *pointer, uint32_t serial, + struct wl_surface *surface, wl_fixed_t x, wl_fixed_t y) +{ + struct wl_cursor_image *img = cursor.cursor->images[0]; + struct wl_buffer *buffer; + + wl_pointer_set_cursor(pointer, serial, cursor.surface, + img->hotspot_x, img->hotspot_y); + buffer = wl_cursor_image_get_buffer(img); + wl_surface_attach(cursor.surface, buffer, 0, 0); + wl_surface_damage(cursor.surface, 0, 0, img->width, img->height); + wl_surface_commit(cursor.surface); +} + +void +ptrleave(void *data, struct wl_pointer *pointer, uint32_t serial, + struct wl_surface *surface) +{ +} + +void +ptrmotion(void *data, struct wl_pointer * pointer, uint32_t serial, + wl_fixed_t x, wl_fixed_t y) +{ + int oldey, oldex, oldsby, oldsey; + + if (IS_SET(MODE_MOUSE)) { + wlmousereportmotion(x, y); + return; + } + + wl.px = wl_fixed_to_int(x); + wl.py = wl_fixed_to_int(y); + + 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(); + + if (oldey != sel.oe.y || oldex != sel.oe.x) + tsetdirt(MIN(sel.nb.y, oldsby), MAX(sel.ne.y, oldsey)); +} + +void +ptrbutton(void * data, struct wl_pointer * pointer, uint32_t serial, + uint32_t time, uint32_t button, uint32_t state) +{ + MouseShortcut *ms; + + if (IS_SET(MODE_MOUSE) && !(wl.xkb.mods & forceselmod)) { + wlmousereportbutton(button, state); + return; + } + + switch (state) { + case WL_POINTER_BUTTON_STATE_RELEASED: + if (button == BTN_MIDDLE) { + selpaste(NULL); + } else if (button == BTN_LEFT) { + if (sel.mode == SEL_READY) { + getbuttoninfo(); + selcopy(serial); + } else + selclear(); + sel.mode = SEL_IDLE; + tsetdirt(sel.nb.y, sel.ne.y); + } + break; + + case WL_POINTER_BUTTON_STATE_PRESSED: + for (ms = mshortcuts; ms < mshortcuts + mshortcutslen; ms++) { + if (button == ms->b && match(ms->mask, wl.xkb.mods)) { + ttysend(ms->s, strlen(ms->s)); + return; + } + } + + if (button == BTN_LEFT) { + /* Clear previous selection, logically and visually. */ + selclear(); + sel.mode = SEL_EMPTY; + sel.type = SEL_REGULAR; + sel.oe.x = sel.ob.x = x2col(wl.px); + sel.oe.y = sel.ob.y = y2row(wl.py); + + /* + * If the user clicks below predefined timeouts + * specific snapping behaviour is exposed. + */ + if (time - sel.tclick2 <= tripleclicktimeout) { + sel.snap = SNAP_LINE; + } else if (time - 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 = time; + } + break; + } +} + +void +ptraxis(void * data, struct wl_pointer * pointer, uint32_t time, uint32_t axis, + wl_fixed_t value) +{ + Axiskey *ak; + int dir = value > 0 ? +1 : -1; + + if (IS_SET(MODE_MOUSE) && !(wl.xkb.mods & forceselmod)) { + wlmousereportaxis(axis, value); + return; + } + + for (ak = ashortcuts; ak < ashortcuts + ashortcutslen; ak++) { + if (axis == ak->axis && dir == ak->dir + && match(ak->mask, wl.xkb.mods)) { + ttysend(ak->s, strlen(ak->s)); + return; + } + } +} + +static void wlloadcursor(void) +{ + char *names[] = { mouseshape, "xterm", "ibeam", "text" }; + int i; + + cursor.theme = wl_cursor_theme_load(NULL, 32, wl.shm); + + for (i = 0; !cursor.cursor && i < LEN(names); i++) + cursor.cursor = wl_cursor_theme_get_cursor(cursor.theme, names[i]); + + cursor.surface = wl_compositor_create_surface(wl.cmp); +} + +void +wldrawcursor(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); + uint32_t 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; + wldrawglyph(og, oldx, oldy); + if (oldx != curx || oldy != term.c.y) { + wl_surface_damage(wl.surface, borderpx + oldx * wl.cw, + borderpx + oldy * wl.ch, wl.cw, wl.ch); + } + + 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 (wl.state & WIN_FOCUSED) { + switch (wl.cursor) { + case 7: /* st-wl 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; + wldrawglyph(g, term.c.x, term.c.y); + break; + case 3: /* Blinking Underline */ + case 4: /* Steady Underline */ + wld_fill_rectangle(wld.renderer, drawcol, + borderpx + curx * wl.cw, + borderpx + (term.c.y + 1) * wl.ch - \ + cursorthickness, + wl.cw, cursorthickness); + break; + case 5: /* Blinking bar */ + case 6: /* Steady bar */ + wld_fill_rectangle(wld.renderer, drawcol, + borderpx + curx * wl.cw, + borderpx + term.c.y * wl.ch, + cursorthickness, wl.ch); + break; + } + } else { + wld_fill_rectangle(wld.renderer, drawcol, + borderpx + curx * wl.cw, + borderpx + term.c.y * wl.ch, + wl.cw - 1, 1); + wld_fill_rectangle(wld.renderer, drawcol, + borderpx + curx * wl.cw, + borderpx + term.c.y * wl.ch, + 1, wl.ch - 1); + wld_fill_rectangle(wld.renderer, drawcol, + borderpx + (curx + 1) * wl.cw - 1, + borderpx + term.c.y * wl.ch, + 1, wl.ch - 1); + wld_fill_rectangle(wld.renderer, drawcol, + borderpx + curx * wl.cw, + borderpx + (term.c.y + 1) * wl.ch - 1, + wl.cw, 1); + } + wl_surface_damage(wl.surface, borderpx + curx * wl.cw, + borderpx + term.c.y * wl.ch, wl.cw, wl.ch); + oldx = curx, oldy = term.c.y; +} + + + +/* Rendering stuff */ +void +wlresize(int col, int row) +{ + union wld_object object; + + wl.tw = MAX(1, col * wl.cw); + wl.th = MAX(1, row * wl.ch); + + wld.oldbuffer = wld.buffer; + wld.buffer = wld_create_buffer(wld.ctx, wl.w, wl.h, + WLD_FORMAT_XRGB8888, 0); + wld_export(wld.buffer, WLD_WAYLAND_OBJECT_BUFFER, &object); + wl.buffer = object.ptr; +} + +void +wlsettitle(char *title) +{ + xdg_toplevel_set_title(wl.xdgtoplevel, title); +} + +void +wlresettitle(void) +{ + wlsettitle(opt_title ? opt_title : "st-wl"); +} + +void +surfenter(void *data, struct wl_surface *surface, struct wl_output *output) +{ + wl.vis++; + if (!(wl.state & WIN_VISIBLE)) + wl.state |= WIN_VISIBLE; +} + +void +surfleave(void *data, struct wl_surface *surface, struct wl_output *output) +{ + if (--wl.vis == 0) + wl.state &= ~WIN_VISIBLE; +} + +void +framedone(void *data, struct wl_callback *callback, uint32_t msecs) +{ + wl_callback_destroy(callback); + wl.framecb = NULL; + if (needdraw && wl.state & WIN_VISIBLE) { + draw(); + } +} + +/* + * Absolute coordinates. + */ +void +wlclear(int x1, int y1, int x2, int y2) +{ + uint32_t color = dc.col[IS_SET(MODE_REVERSE) ? defaultfg : defaultbg]; + + wld_fill_rectangle(wld.renderer, color, x1, y1, x2 - x1, y2 - y1); +} + +void +xdgsurfconfigure(void *data, struct xdg_surface *surf, uint32_t serial) +{ + xdg_surface_ack_configure(surf, serial); +} + +void +xdgtoplevelconfigure(void *data, struct xdg_toplevel *toplevel, + int32_t w, int32_t h, struct wl_array *states) +{ + if (w == wl.w && h == wl.h) + return; + cresize(w, h); + if (wl.configured) + ttyresize(); + else + wl.configured = true; +} + +void +xdgtoplevelclose(void *data, struct xdg_toplevel *toplevel) +{ + /* Send SIGHUP to shell */ + kill(pid, SIGHUP); + exit(0); +} + + + +/* Font stuff */ +uchar +sixd_to_8bit(int x) +{ + return x == 0 ? 0 : 0x37 + 0x28 * x; +} + +int +wlloadcolor(int i, const char *name, uint32_t *color) +{ + if (!name) { + if (BETWEEN(i, 16, 255)) { /* 256 color */ + if (i < 6*6*6+16) { /* same colors as xterm */ + *color = 0xff << 24 | sixd_to_8bit(((i-16)/36)%6) << 16 + | sixd_to_8bit(((i-16)/6)%6) << 8 + | sixd_to_8bit(((i-16)/1)%6); + } else { /* greyscale */ + *color = 0xff << 24 | (0x8 + 0xa * (i-(6*6*6+16))) * 0x10101; + } + return true; + } else + name = colorname[i]; + } + + return wld_lookup_named_color(name, color); +} + +void +wlloadcols(void) +{ + int i; + + dc.collen = MAX(colornamelen, 256); + dc.col = xmalloc(dc.collen * sizeof(uint32_t)); + + for (i = 0; i < dc.collen; i++) + if (!wlloadcolor(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); + } +} + +int +wlsetcolorname(int x, const char *name) +{ + uint32_t color; + + if (!BETWEEN(x, 0, dc.collen)) + return 1; + + if (!wlloadcolor(x, name, &color)) + return 1; + + dc.col[x] = color; + + return 0; +} + +int +wlloadfont(Font *f, FcPattern *pattern) +{ + FcPattern *configured; + FcPattern *match; + FcResult result; + struct wld_extents 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); + FcDefaultSubstitute(configured); + + match = FcFontMatch(NULL, configured, &result); + if (!match) { + FcPatternDestroy(configured); + return 1; + } + + if (!(f->match = wld_font_open_pattern(wld.fontctx, match))) { + FcPatternDestroy(configured); + FcPatternDestroy(match); + return 1; + } + + if ((FcPatternGetInteger(pattern, "slant", 0, &wantattr) == + FcResultMatch)) { + /* + * Check if xft was unable to find a font with the appropriate + * slant but gave us one anyway. Try to mitigate. + */ + if ((FcPatternGetInteger(match, "slant", 0, + &haveattr) != FcResultMatch) || haveattr < wantattr) { + f->badslant = 1; + fputs("st-wl: font slant does not match\n", stderr); + } + } + + if ((FcPatternGetInteger(pattern, "weight", 0, &wantattr) == + FcResultMatch)) { + if ((FcPatternGetInteger(match, "weight", 0, + &haveattr) != FcResultMatch) || haveattr != wantattr) { + f->badweight = 1; + fputs("st-wl: font weight does not match\n", stderr); + } + } + + + wld_font_text_extents(f->match, 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; + + f->height = f->ascent + f->descent; + f->width = DIVCEIL(extents.advance, strlen(ascii_printable)); + + return 0; +} + +void +wlloadfonts(char *fontstr, double fontsize) +{ + FcPattern *pattern; + double fontval; + float ceilf(float); + + if (fontstr[0] == '-') { + /* XXX: need XftXlfdParse equivalent */ + pattern = NULL; + } else { + pattern = FcNameParse((FcChar8 *)fontstr); + } + + if (!pattern) + die("st-wl: 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; + } + + FcConfigSubstitute(0, pattern, FcMatchPattern); + FcDefaultSubstitute(pattern); + + if (wlloadfont(&dc.font, pattern)) + die("st-wl: can't open font %s\n", fontstr); + + if (usedfontsize < 0) { + FcPatternGetDouble(dc.font.pattern, + FC_PIXEL_SIZE, 0, &fontval); + usedfontsize = fontval; + if (fontsize == 0) + defaultfontsize = fontval; + } + + /* Setting character width and height. */ + wl.cw = ceilf(dc.font.width * cwscale); + wl.ch = ceilf(dc.font.height * chscale); + + FcPatternDel(pattern, FC_SLANT); + FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ITALIC); + if (wlloadfont(&dc.ifont, pattern)) + die("st-wl: can't open font %s\n", fontstr); + + FcPatternDel(pattern, FC_WEIGHT); + FcPatternAddInteger(pattern, FC_WEIGHT, FC_WEIGHT_BOLD); + if (wlloadfont(&dc.ibfont, pattern)) + die("st-wl: can't open font %s\n", fontstr); + + FcPatternDel(pattern, FC_SLANT); + FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ROMAN); + if (wlloadfont(&dc.bfont, pattern)) + die("st-wl: can't open font %s\n", fontstr); + + FcPatternDestroy(pattern); +} + +void +wlunloadfont(Font *f) +{ + wld_font_close(f->match); + FcPatternDestroy(f->pattern); + if (f->set) + FcFontSetDestroy(f->set); +} + +void +wlunloadfonts(void) +{ + /* Free the loaded fonts in the font cache. */ + while (frclen > 0) + wld_font_close(frc[--frclen].font); + + wlunloadfont(&dc.font); + wlunloadfont(&dc.bfont); + wlunloadfont(&dc.ifont); + wlunloadfont(&dc.ibfont); +} + +/* + * TODO: Implement something like XftDrawGlyphFontSpec in wld, and then apply a + * similar patch to ae1923d27533ff46400d93765e971558201ca1ee + */ + +void +wldraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) +{ + int winx = borderpx + x * wl.cw, winy = borderpx + y * wl.ch, + width = charlen * wl.cw, xp, i; + int frcflags, charexists; + int u8fl, u8fblen, u8cblen, doesexist; + char *u8c, *u8fs; + Rune unicodep; + Font *font = &dc.font; + FcResult fcres; + FcPattern *fcpattern, *fontpattern; + FcFontSet *fcsets[] = { NULL }; + FcCharSet *fccharset; + uint32_t fg, bg, temp; + int oneatatime; + + frcflags = FRC_NORMAL; + + /* 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; + font = &dc.ibfont; + frcflags = FRC_ITALICBOLD; + } else if (base.mode & ATTR_ITALIC) { + if (dc.ifont.badslant) + base.fg = defaultattr; + font = &dc.ifont; + frcflags = FRC_ITALIC; + } else if (base.mode & ATTR_BOLD) { + if (dc.bfont.badweight) + base.fg = defaultattr; + font = &dc.ifont; + frcflags = FRC_BOLD; + } + + if (IS_TRUECOL(base.fg)) { + fg = base.fg | 0xff000000; + } else { + fg = dc.col[base.fg]; + } + + if (IS_TRUECOL(base.bg)) { + bg = base.bg | 0xff000000; + } else { + bg = dc.col[base.bg]; + } + + if (base.mode & ATTR_BOLD) { + /* + * change basic system colors [0-7] + * to bright system colors [8-15] + */ + if (BETWEEN(base.fg, 0, 7) && !(base.mode & ATTR_FAINT)) + fg = dc.col[base.fg + 8]; + + if (base.mode & ATTR_ITALIC) { + font = &dc.ibfont; + frcflags = FRC_ITALICBOLD; + } else { + font = &dc.bfont; + frcflags = FRC_BOLD; + } + } + + if (IS_SET(MODE_REVERSE)) { + if (fg == dc.col[defaultfg]) { + fg = dc.col[defaultbg]; + } else { + fg = ~(fg & 0xffffff); + } + + if (bg == dc.col[defaultbg]) { + bg = dc.col[defaultfg]; + } else { + bg = ~(bg & 0xffffff); + } + } + + if (base.mode & ATTR_REVERSE) { + temp = fg; + fg = bg; + bg = temp; + } + + if (base.mode & ATTR_FAINT && !(base.mode & ATTR_BOLD)) { + fg = (fg & (0xff << 24)) + | ((((fg >> 16) & 0xff) / 2) << 16) + | ((((fg >> 8) & 0xff) / 2) << 8) + | ((fg & 0xff) / 2); + } + + 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) { + wlclear(0, (y == 0)? 0 : winy, borderpx, + ((y >= term.row-1)? wl.h : (winy + wl.ch))); + } + if (x + charlen >= term.col) { + wlclear(winx + width, (y == 0)? 0 : winy, wl.w, + ((y >= term.row-1)? wl.h : (winy + wl.ch))); + } + if (y == 0) + wlclear(winx, 0, winx + width, borderpx); + if (y == term.row-1) + wlclear(winx, winy + wl.ch, winx + width, wl.h); + + /* Clean up the region we want to draw to. */ + wld_fill_rectangle(wld.renderer, bg, winx, winy, width, wl.ch); + + for (xp = winx; bytelen > 0;) { + /* + * Search for the range in the to be printed string of glyphs + * that are in the main font. Then print that range. If + * some glyph is found that is not in the font, do the + * fallback dance. + */ + u8fs = s; + u8fblen = 0; + u8fl = 0; + oneatatime = font->width != wl.cw; + for (;;) { + u8c = s; + u8cblen = utf8decode(s, &unicodep, UTF_SIZ); + s += u8cblen; + bytelen -= u8cblen; + + doesexist = wld_font_ensure_char(font->match, unicodep); + if (doesexist) { + u8fl++; + u8fblen += u8cblen; + if (!oneatatime && bytelen > 0) + continue; + } + + if (u8fl > 0) { + wld_draw_text(wld.renderer, + font->match, fg, xp, + winy + font->ascent, + u8fs, u8fblen, NULL); + xp += wl.cw * u8fl; + } + break; + } + if (doesexist) { + if (oneatatime) + continue; + break; + } + + /* Search the font cache. */ + for (i = 0; i < frclen; i++) { + charexists = wld_font_ensure_char(frc[i].font, unicodep); + /* Everything correct. */ + if (charexists && frc[i].flags == frcflags) + break; + /* We got a default font for a not found glyph. */ + if (!charexists && frc[i].flags == frcflags \ + && frc[i].unicodep == unicodep) { + break; + } + } + + /* Nothing was found. */ + if (i >= 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, unicodep); + 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; + wld_font_close(frc[frclen].font); + frc[frclen].unicodep = 0; + } + + frc[frclen].font = wld_font_open_pattern(wld.fontctx, + fontpattern); + frc[frclen].flags = frcflags; + frc[frclen].unicodep = unicodep; + + i = frclen; + frclen++; + + FcPatternDestroy(fcpattern); + FcCharSetDestroy(fccharset); + } + + wld_draw_text(wld.renderer, frc[i].font, fg, + xp, winy + frc[i].font->ascent, + u8c, u8cblen, NULL); + + xp += wl.cw * wcwidth(unicodep); + } + + if (base.mode & ATTR_UNDERLINE) { + wld_fill_rectangle(wld.renderer, fg, winx, winy + font->ascent + 1, + width, 1); + } + + if (base.mode & ATTR_STRUCK) { + wld_fill_rectangle(wld.renderer, fg, winx, winy + 2 * font->ascent / 3, + width, 1); + } +} + +void +wldrawglyph(Glyph g, int x, int y) +{ + static char buf[UTF_SIZ]; + size_t len = utf8encode(g.u, buf); + int width = g.mode & ATTR_WIDE ? 2 : 1; + + wldraws(buf, g, x, y, width, len); +} + + + +/* Technical stuff */ +void +wmping(void *data, struct xdg_wm_base *wm, uint32_t serial) +{ + xdg_wm_base_pong(wm, serial); +} + +void +regglobal(void *data, struct wl_registry *registry, uint32_t name, + const char *interface, uint32_t version) +{ + if (strcmp(interface, "wl_compositor") == 0) { + wl.cmp = wl_registry_bind(registry, name, &wl_compositor_interface, 3); + } else if (strcmp(interface, "xdg_wm_base") == 0) { + wl.wm = wl_registry_bind(registry, name, &xdg_wm_base_interface, 1); + xdg_wm_base_add_listener(wl.wm, &wmlistener, NULL); + } else if (strcmp(interface, "wl_shm") == 0) { + wl.shm = wl_registry_bind(registry, name, &wl_shm_interface, 1); + } else if (strcmp(interface, "wl_seat") == 0) { + wl.seat = wl_registry_bind(registry, name, &wl_seat_interface, 4); + } else if (strcmp(interface, "wl_data_device_manager") == 0) { + wl.datadevmanager = wl_registry_bind(registry, name, + &wl_data_device_manager_interface, 1); + } else if (strcmp(interface, "wl_output") == 0) { + /* bind to outputs so we can get surface enter events */ + wl_registry_bind(registry, name, &wl_output_interface, 2); + } +} + +void +regglobalremove(void *data, struct wl_registry *registry, uint32_t name) +{ +} + +void +wlinit(void) +{ + struct wl_registry *registry; + + if (!(wl.dpy = wl_display_connect(NULL))) + die("Can't open display\n"); + + registry = wl_display_get_registry(wl.dpy); + wl_registry_add_listener(registry, ®listener, NULL); + wld.ctx = wld_wayland_create_context(wl.dpy, WLD_ANY); + wld.renderer = wld_create_renderer(wld.ctx); + + wl_display_roundtrip(wl.dpy); + + if (!wl.shm) + die("Display has no SHM\n"); + if (!wl.seat) + die("Display has no seat\n"); + if (!wl.datadevmanager) + die("Display has no data device manager\n"); + if (!wl.wm) + die("Display has no window manager\n"); + + wl.keyboard = wl_seat_get_keyboard(wl.seat); + wl_keyboard_add_listener(wl.keyboard, &kbdlistener, NULL); + wl.pointer = wl_seat_get_pointer(wl.seat); + wl_pointer_add_listener(wl.pointer, &ptrlistener, NULL); + wl.datadev = wl_data_device_manager_get_data_device(wl.datadevmanager, + wl.seat); + wl_data_device_add_listener(wl.datadev, &datadevlistener, NULL); + + /* font */ + if (!FcInit()) + die("Could not init fontconfig.\n"); + + usedfont = (opt_font == NULL)? font : opt_font; + wld.fontctx = wld_font_create_context(); + wlloadfonts(usedfont, 0); + + wlloadcols(); + wlloadcursor(); + + wl.vis = 0; + wl.h = 2 * borderpx + term.row * wl.ch; + wl.w = 2 * borderpx + term.col * wl.cw; + + wl.surface = wl_compositor_create_surface(wl.cmp); + wl_surface_add_listener(wl.surface, &surflistener, NULL); + + wl.xdgsurface = xdg_wm_base_get_xdg_surface(wl.wm, wl.surface); + xdg_surface_add_listener(wl.xdgsurface, &xdgsurflistener, NULL); + wl.xdgtoplevel = xdg_surface_get_toplevel(wl.xdgsurface); + xdg_toplevel_add_listener(wl.xdgtoplevel, &xdgtoplevellistener, NULL); + xdg_toplevel_set_app_id(wl.xdgtoplevel, opt_class ? opt_class : termname); + + wl_surface_commit(wl.surface); + + wl.xkb.ctx = xkb_context_new(0); + wlresettitle(); +} + +void +run(void) +{ + fd_set rfd; + int wlfd = wl_display_get_fd(wl.dpy), blinkset = 0; + struct timespec drawtimeout, *tv = NULL, now, last, lastblink; + ulong msecs; + + /* Look for initial configure. */ + wl_display_roundtrip(wl.dpy); + if (!wl.configured) + cresize(wl.w, wl.h); + ttynew(); + ttyresize(); + draw(); + + clock_gettime(CLOCK_MONOTONIC, &last); + lastblink = last; + + for (;;) { + FD_ZERO(&rfd); + FD_SET(cmdfd, &rfd); + FD_SET(wlfd, &rfd); + + if (pselect(MAX(wlfd, 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(wlfd, &rfd)) { + if (wl_display_dispatch(wl.dpy) == -1) + die("Connection error\n"); + } + + clock_gettime(CLOCK_MONOTONIC, &now); + msecs = -1; + + if (blinkset && blinktimeout) { + if (TIMEDIFF(now, lastblink) >= blinktimeout) { + tsetdirtattr(ATTR_BLINK); + term.mode ^= MODE_BLINK; + lastblink = now; + } else { + msecs = MIN(msecs, blinktimeout - \ + TIMEDIFF(now, lastblink)); + } + } + if (repeat.len > 0) { + if (TIMEDIFF(now, repeat.last) >= \ + (repeat.started ? keyrepeatinterval : \ + keyrepeatdelay)) { + repeat.started = true; + repeat.last = now; + ttysend(repeat.str, repeat.len); + } else { + msecs = MIN(msecs, (repeat.started ? \ + keyrepeatinterval : keyrepeatdelay) - \ + TIMEDIFF(now, repeat.last)); + } + } + + if (needdraw && wl.state & WIN_VISIBLE) { + if (!wl.framecb) { + draw(); + } + } + + if (msecs == -1) { + tv = NULL; + } else { + drawtimeout.tv_nsec = 1E6 * msecs; + drawtimeout.tv_sec = 0; + tv = &drawtimeout; + } + + wl_display_dispatch_pending(wl.dpy); + wl_display_flush(wl.dpy); + } +} + +int +main(int argc, char *argv[]) +{ + wl.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 '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-wl 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, ""); + tnew(MAX(cols, 1), MAX(rows, 1)); + wlinit(); + selinit(); + run(); + + return 0; +} + From 96ebe1009020948387445bf694688d7e963f474c Mon Sep 17 00:00:00 2001 From: ian <42294085+ianbeyst@users.noreply.github.com> Date: Thu, 13 Jun 2019 13:18:21 +0200 Subject: [PATCH 117/129] cleaned up st-wl.c --- st-wl.c | 408 +++++++++++++++++++------------------------------------- st-wl.h | 53 ++------ wl.c | 329 +++++++++++++++++++++++++++++++++++---------- 3 files changed, 409 insertions(+), 381 deletions(-) diff --git a/st-wl.c b/st-wl.c index 4eadd82..bde4a38 100644 --- a/st-wl.c +++ b/st-wl.c @@ -3,8 +3,6 @@ #include #include #include -/* for BTN_* definitions */ -#include #include #include #include @@ -14,7 +12,6 @@ #include #include #include -#include #include #include #include @@ -24,16 +21,22 @@ #include #include #include -#include -#include -#include -#include -#include #include #include +/* for BTN_* definitions */ +#include +#include +#include +#include -#include "arg.h" -#include "xdg-shell-client-protocol.h" +/* Wayland */ +#include +//#include +//#include "xdg-shell-client-protocol.h" +//#include +//#include + +//#include "arg.h" char *argv0; @@ -47,32 +50,20 @@ char *argv0; #include #endif - /* Arbitrary sizes */ #define UTF_INVALID 0xFFFD +#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 DRAW_BUF_SIZ 20*1024 -#define XK_ANY_MOD UINT_MAX -#define XK_NO_MOD 0 -#define XK_SWITCH_MOD (1<<13) - -#define AXIS_HORIZONTAL WL_POINTER_AXIS_HORIZONTAL_SCROLL /* macros */ +#define NUMMAXLEN(x) ((int)(sizeof(x) * 2.56 + 0.5) + 1) #define DEFAULT(a, b) (a) = (a) ? (a) : (b) #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 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 TRUERED(x) (((x) & 0xff0000) >> 8) -#define TRUEGREEN(x) (((x) & 0xff00)) -#define TRUEBLUE(x) (((x) & 0xff) << 8) /* constants */ #define ISO14755CMD "dmenu -p codepoint: 0) { - len = MIN(sizeof buf, left); - memcpy(buf, str, len); - selwritebuf(buf, len); - left -= len; - str += len; - } - } else { - pipe(fds); - wl_data_offer_receive(wl.seloffer, "text/plain", fds[1]); - wl_display_flush(wl.dpy); - close(fds[1]); - while ((len = read(fds[0], buf, sizeof buf)) > 0) { - selwritebuf(buf, len); - } - close(fds[0]); - } - if (IS_SET(MODE_BRCKTPASTE)) - ttywrite("\033[201~", 6); - } + // TODO: Check what xclippaste() does } void @@ -641,22 +621,6 @@ selclear(void) tsetdirt(sel.nb.y, sel.ne.y); } -void -wlsetsel(char *str, uint32_t serial) -{ - free(sel.primary); - sel.primary = str; - - if (str) { - sel.source = wl_data_device_manager_create_data_source(wl.datadevmanager); - wl_data_source_add_listener(sel.source, &datasrclistener, NULL); - wl_data_source_offer(sel.source, "text/plain; charset=utf-8"); - } else { - sel.source = NULL; - } - wl_data_device_set_selection(wl.datadev, sel.source, serial); -} - void die(const char *errstr, ...) { @@ -701,6 +665,7 @@ execsh(void) setenv("SHELL", sh, 1); setenv("HOME", pw->pw_dir, 1); setenv("TERM", termname, 1); + // xsetenv(); signal(SIGCHLD, SIG_DFL); signal(SIGHUP, SIG_DFL); @@ -726,7 +691,7 @@ sigchld(int a) return; if (!WIFEXITED(stat) || WEXITSTATUS(stat)) - die("child finished with error '%d'\n", WEXITSTATUS(stat)); + die("child finished with error '%d'\n", stat); exit(0); } @@ -1515,18 +1480,22 @@ tsetmode(int priv, int set, int *args, int narg) MODBIT(term.mode, !set, MODE_HIDE); break; case 9: /* X10 mouse compatibility mode */ + // xsetpointermotion(0); MODBIT(term.mode, 0, MODE_MOUSE); MODBIT(term.mode, set, MODE_MOUSEX10); break; case 1000: /* 1000: report button press */ + // xsetpointermotion(0); MODBIT(term.mode, 0, MODE_MOUSE); MODBIT(term.mode, 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); break; case 1003: /* 1003: enable all mouse motions */ + // xsetpointermotion(0); MODBIT(term.mode, 0, MODE_MOUSE); MODBIT(term.mode, set, MODE_MOUSEMANY); break; @@ -2165,10 +2134,8 @@ tcontrolcode(uchar ascii) } else { if (!(wl.state & WIN_FOCUSED)) wlseturgency(1); - /* XXX: No bell on wayland - * if (bellvolume) - * XkbBell(xw.dpy, xw.win, bellvolume, (Atom)NULL); - */ + // if (bellvolume) // XXX: No bell on wayland + // XkbBell(xw.dpy, xw.win, bellvolume, (Atom)NULL); } break; case '\033': /* ESC */ @@ -2358,7 +2325,7 @@ tputc(Rune u) */ if (term.esc & ESC_STR) { if (u == '\a' || u == 030 || u == 032 || u == 033 || - ISCONTROLC1(u)) { + ISCONTROLC1(u)) { term.esc &= ~(ESC_START|ESC_STR|ESC_DCS); if (IS_SET(MODE_SIXEL)) { /* TODO: render sixel */; @@ -2508,6 +2475,9 @@ tresize(int col, int row) free(term.alt[i]); } + /* resize to new width */ + // term.specbuf = xrealloc(term.specbuf, col * sizeof(GlyphFontSpec)); + /* resize to new height */ term.line = xrealloc(term.line, row * sizeof(Line)); term.alt = xrealloc(term.alt, row * sizeof(Line)); @@ -2575,8 +2545,7 @@ wlzoomabs(const Arg *arg) redraw(); /* XXX: Should the window size be updated here because wayland doesn't * have a notion of hints? - * xhints(); - */ + * xhints(); */ } void @@ -2591,84 +2560,22 @@ wlzoomreset(const Arg *arg) } void -redraw(void) -{ - tfulldirt(); -} - -void -draw(void) +wlresettitle(void) { - int y, y0; - - for (y = 0; y <= term.bot; ++y) { - if (!term.dirty[y]) - continue; - for (y0 = y; y <= term.bot && term.dirty[y]; ++y); - wl_surface_damage(wl.surface, 0, borderpx + y0 * wl.ch, - wl.w, (y - y0) * wl.ch); - } - - wld_set_target_buffer(wld.renderer, wld.buffer); - drawregion(0, 0, term.col, term.row); - wl.framecb = wl_surface_frame(wl.surface); - wl_callback_add_listener(wl.framecb, &framelistener, NULL); - wld_flush(wld.renderer); - wl_surface_attach(wl.surface, wl.buffer, 0, 0); - wl_surface_commit(wl.surface); - /* need to wait to destroy the old buffer until we commit the new - * buffer */ - if (wld.oldbuffer) { - wld_buffer_unreference(wld.oldbuffer); - wld.oldbuffer = 0; - } - needdraw = false; + wlsettitle(opt_title ? opt_title : "st-wl"); } void -drawregion(int x1, int y1, int x2, int y2) +redraw(void) { - int ic, ib, x, y, ox; - Glyph base, new; - char buf[DRAW_BUF_SIZ]; - int ena_sel = sel.ob.x != -1 && sel.alt == IS_SET(MODE_ALTSCREEN); - - for (y = y1; y < y2; y++) { - if (!term.dirty[y]) - continue; - - term.dirty[y] = 0; - base = term.line[y][0]; - ic = ib = ox = 0; - for (x = x1; x < x2; x++) { - new = term.line[y][x]; - if (new.mode == ATTR_WDUMMY) - continue; - if (ena_sel && selected(x, y)) - new.mode ^= ATTR_REVERSE; - if (ib > 0 && (ATTRCMP(base, new) - || ib >= DRAW_BUF_SIZ-UTF_SIZ)) { - wldraws(buf, base, ox, y, ic, ib); - ic = ib = 0; - } - if (ib == 0) { - ox = x; - base = new; - } - - ib += utf8encode(new.u, buf+ib); - ic += (new.mode & ATTR_WIDE)? 2 : 1; - } - if (ib > 0) - wldraws(buf, base, ox, y, ic, ib); - } - wldrawcursor(); + tfulldirt(); + // draw(); // Removed in wayland branch } -void -wlseturgency(int add) +int +match(uint mask, uint state) { - /* XXX: no urgency equivalent yet in wayland */ + return mask == MOD_MASK_ANY || mask == (state & ~(ignoremod)); } void @@ -2677,98 +2584,61 @@ numlock(const Arg *dummy) term.numlock ^= 1; } -void -cresize(int width, int height) +char* +kmap(xkb_keysym_t k, uint state) { - int col, row; - - if (width != 0) - wl.w = width; - if (height != 0) - wl.h = height; + Key *kp; + int i; - col = (wl.w - 2 * borderpx) / wl.cw; - row = (wl.h - 2 * borderpx) / wl.ch; + /* 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; + } - tresize(col, row); - wlresize(col, row); -} + for (kp = key; kp < key + LEN(key); kp++) { + if (kp->k != k) + continue; -void -datadevoffer(void *data, struct wl_data_device *datadev, - struct wl_data_offer *offer) -{ - wl_data_offer_add_listener(offer, &dataofferlistener, NULL); -} + if (!match(kp->mask, state)) + continue; -void -datadeventer(void *data, struct wl_data_device *datadev, uint32_t serial, - struct wl_surface *surf, wl_fixed_t x, wl_fixed_t y, - struct wl_data_offer *offer) -{ -} + if (IS_SET(MODE_APPKEYPAD) ? kp->appkey < 0 : kp->appkey > 0) + continue; + if (term.numlock && kp->appkey == 2) + continue; -void -datadevleave(void *data, struct wl_data_device *datadev) -{ -} + if (IS_SET(MODE_APPCURSOR) ? kp->appcursor < 0 : kp->appcursor > 0) + continue; -void -datadevmotion(void *data, struct wl_data_device *datadev, uint32_t time, - wl_fixed_t x, wl_fixed_t y) -{ -} + if (IS_SET(MODE_CRLF) ? kp->crlf < 0 : kp->crlf > 0) + continue; -void -datadevdrop(void *data, struct wl_data_device *datadev) -{ -} + return kp->s; + } -void -datadevselection(void *data, struct wl_data_device *datadev, - struct wl_data_offer *offer) -{ - if (offer && (uintptr_t) wl_data_offer_get_user_data(offer) == 1) - wl.seloffer = offer; - else - wl.seloffer = NULL; + return NULL; } void -dataofferoffer(void *data, struct wl_data_offer *offer, const char *mimetype) +cresize(int width, int height) { - /* mark the offer as usable if it supports plain text */ - if (strncmp(mimetype, "text/plain", 10) == 0) - wl_data_offer_set_user_data(offer, (void *)(uintptr_t) 1); -} + int col, row; -void -datasrctarget(void *data, struct wl_data_source *source, const char *mimetype) -{ -} + if (width != 0) + wl.w = width; + if (height != 0) + wl.h = height; -void -datasrcsend(void *data, struct wl_data_source *source, const char *mimetype, - int32_t fd) -{ - char *buf = sel.primary; - int len = strlen(sel.primary); - ssize_t ret; - while ((ret = write(fd, buf, MIN(len, BUFSIZ))) > 0) { - len -= ret; - buf += ret; - } - close(fd); -} + col = (wl.w - 2 * borderpx) / wl.cw; + row = (wl.h - 2 * borderpx) / wl.ch; -void -datasrccancelled(void *data, struct wl_data_source *source) -{ - if (sel.source == source) { - sel.source = NULL; - selclear(); - } - wl_data_source_destroy(source); + tresize(col, row); + wlresize(col, row); } void diff --git a/st-wl.h b/st-wl.h index 4bf9d13..f791170 100644 --- a/st-wl.h +++ b/st-wl.h @@ -23,6 +23,7 @@ #define LIMIT(x, a, b) (x) = (x) < (a) ? (a) : (x) > (b) ? (b) : (x) #define IS_SET(flag) ((term.mode & (flag)) != 0) +#define TRUECOLOR(r,g,b) (1 << 24 | (r) << 16 | (g) << 8 | (b)) /* type declarations */ @@ -33,16 +34,6 @@ typedef unsigned short ushort; typedef uint_least32_t Rune; -typedef struct { - xkb_keysym_t 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; - typedef struct { Rune u; /* character code */ ushort mode; /* attribute flags */ @@ -149,13 +140,6 @@ typedef struct { struct timespec last; } Repeat; -typedef struct { - struct wld_context *ctx; - struct wld_font_context *fontctx; - struct wld_renderer *renderer; - struct wld_buffer *buffer, *oldbuffer; -} WLD; - typedef struct { int mode; int type; @@ -186,7 +170,9 @@ void *xmalloc(size_t); size_t utf8decode(char *, Rune *, size_t); size_t utf8encode(Rune, char *); void usage(void); +char *kmap(xkb_keysym_t, uint); void cresize(int, int); +int match(uint, uint); void ttynew(void); void ttysend(char *, size_t); size_t ttyread(void); @@ -195,6 +181,7 @@ void ttyresize(void); void draw(void); int cmdfd; void die(const char *, ...); +void redraw(void); int tattrset(int); void tsetdirtattr(int); @@ -208,6 +195,10 @@ void selnormalize(void); void selclear(void); void selcopy(uint32_t); int selected(int, int); +char *getsel(void); +int x2col(int); +int y2row(int); + void wlsettitle(char *); void wlresettitle(void); @@ -219,22 +210,9 @@ void wlloadfonts(char *, double); void wlunloadfonts(void); void wldrawcursor(void); void wldraws(char *, Glyph, int, int, int, int); +void wlseturgency(int); void framedone(void *, struct wl_callback *, uint32_t); - -void datadevoffer(void *, struct wl_data_device *, - struct wl_data_offer *); -void datadeventer(void *, struct wl_data_device *, uint32_t, - struct wl_surface *, wl_fixed_t, wl_fixed_t, struct wl_data_offer *); -void datadevleave(void *, struct wl_data_device *); -void datadevmotion(void *, struct wl_data_device *, uint32_t, - wl_fixed_t x, wl_fixed_t y); -void datadevdrop(void *, struct wl_data_device *); -void datadevselection(void *, struct wl_data_device *, - struct wl_data_offer *); -void dataofferoffer(void *, struct wl_data_offer *, const char *); -void datasrctarget(void *, struct wl_data_source *, const char *); -void datasrcsend(void *, struct wl_data_source *, const char *, int32_t); -void datasrccancelled(void *, struct wl_data_source *); +void wlselpaste(void); @@ -305,7 +283,6 @@ enum window_state { }; pid_t pid; -WLD wld; Wayland wl; Term term; Repeat repeat; @@ -371,17 +348,7 @@ extern uint selmasks[]; extern size_t selmaskslen; extern char ascii_printable[]; extern uint ignoremod; -extern Key key[]; extern size_t keylen; /* function definitions used in config.h */ -void numlock(const Arg *); void selpaste(const Arg *); -void wlzoom(const Arg *); -void wlzoomabs(const Arg *); -void wlzoomreset(const Arg *); -void printsel(const Arg *); -void printscreen(const Arg *); -void iso14755(const Arg *); -void toggleprinter(const Arg *); -void sendbreak(const Arg *); diff --git a/wl.c b/wl.c index 658eb3a..157733b 100644 --- a/wl.c +++ b/wl.c @@ -38,11 +38,16 @@ +#define DRAW_BUF_SIZ 20*1024 + /* Macros */ #define DIVCEIL(n, d) (((n) + ((d) - 1)) / (d)) #define TIMEDIFF(t1, t2) ((t1.tv_sec-t2.tv_sec)*1000 + \ (t1.tv_nsec-t2.tv_nsec)/1E6) +#define ATTRCMP(a, b) ((a).mode != (b).mode || (a).fg != (b).fg || \ + (a).bg != (b).bg) + #define IS_TRUECOL(x) (1 << 24 & (x)) @@ -77,11 +82,17 @@ typedef struct { struct wl_surface *surface; } Cursor; +typedef struct { + struct wld_context *ctx; + struct wld_font_context *fontctx; + struct wld_renderer *renderer; + struct wld_buffer *buffer, *oldbuffer; +} WLD; + /* Function declarations */ static void run(void); -static inline int match(uint, uint); static void kbdkeymap(void *, struct wl_keyboard *, uint32_t, int32_t, uint32_t); static void kbdenter(void *, struct wl_keyboard *, uint32_t, @@ -94,8 +105,6 @@ static void kbdmodifiers(void *, struct wl_keyboard *, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t); static void kbdrepeatinfo(void *, struct wl_keyboard *, int32_t, int32_t); -static int x2col(int); -static int y2row(int); static void ptrenter(void *, struct wl_pointer *, uint32_t, struct wl_surface *, wl_fixed_t, wl_fixed_t); static void ptrleave(void *, struct wl_pointer *, uint32_t, @@ -107,12 +116,17 @@ static void ptrbutton(void *, struct wl_pointer *, uint32_t, uint32_t, static void ptraxis(void *, struct wl_pointer *, uint32_t, uint32_t, wl_fixed_t); static void wlloadcursor(void); +static void wlsetsel(char*, uint32_t); + + static inline uchar sixd_to_8bit(int); static int wlloadfont(Font *, FcPattern *); static void wlunloadfont(Font *f); static void wldrawglyph(Glyph, int, int); static void wlclear(int, int, int, int); +static void drawregion(int, int, int, int); + static void regglobal(void *, struct wl_registry *, uint32_t, const char *, uint32_t); @@ -125,9 +139,24 @@ static void xdgtoplevelconfigure(void *, struct xdg_toplevel *, int32_t, int32_t, struct wl_array *); static void xdgtoplevelclose(void *, struct xdg_toplevel *); +static void datadevoffer(void *, struct wl_data_device *, + struct wl_data_offer *); +static void datadeventer(void *, struct wl_data_device *, uint32_t, + struct wl_surface *, wl_fixed_t, wl_fixed_t, struct wl_data_offer *); +static void datadevleave(void *, struct wl_data_device *); +static void datadevmotion(void *, struct wl_data_device *, uint32_t, + wl_fixed_t x, wl_fixed_t y); +static void datadevdrop(void *, struct wl_data_device *); +static void datadevselection(void *, struct wl_data_device *, + struct wl_data_offer *); +static void dataofferoffer(void *, struct wl_data_offer *, const char *); +static void datasrctarget(void *, struct wl_data_source *, const char *); +static void datasrcsend(void *, struct wl_data_source *, const char *, int32_t); +static void datasrccancelled(void *, struct wl_data_source *); /* Globals */ +static struct wl_callback_listener framelistener = { framedone }; static struct wl_registry_listener reglistener = { regglobal, regglobalremove }; static struct wl_surface_listener surflistener = { surfenter, surfleave }; static struct wl_keyboard_listener kbdlistener = @@ -141,8 +170,12 @@ static struct xdg_toplevel_listener xdgtoplevellistener = static struct wl_data_device_listener datadevlistener = { datadevoffer, datadeventer, datadevleave, datadevmotion, datadevdrop, datadevselection }; +static struct wl_data_source_listener datasrclistener = + { datasrctarget, datasrcsend, datasrccancelled }; +static struct wl_data_offer_listener dataofferlistener = { dataofferoffer }; static DC dc; +static WLD wld; static Cursor cursor; static int oldbutton = 3; /* button event on startup: 3 = release */ static int oldx, oldy; @@ -227,52 +260,6 @@ kbdleave(void *data, struct wl_keyboard *keyboard, uint32_t serial, repeat.len = 0; } -int -match(uint mask, uint state) -{ - return mask == MOD_MASK_ANY || mask == (state & ~(ignoremod)); -} - -char* -kmap(xkb_keysym_t k, uint state) -{ - Key *kp; - int i; - - /* Check for mapped keys out of X11 function keys. */ - for (i = 0; i < mappedkeyslen; i++) { - if (mappedkeys[i] == k) - break; - } - if (i == mappedkeyslen) { - if ((k & 0xFFFF) < 0xFD00) - return NULL; - } - - for (kp = key; kp < key + keylen; 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 kbdkey(void *data, struct wl_keyboard *keyboard, uint32_t serial, uint32_t time, uint32_t key, uint32_t state) @@ -380,24 +367,6 @@ kbdrepeatinfo(void *data, struct wl_keyboard *keyboard, int32_t rate, /* Mouse stuff */ -int -x2col(int x) -{ - x -= borderpx; - x /= wl.cw; - - return LIMIT(x, 0, term.col-1); -} - -int -y2row(int y) -{ - y -= borderpx; - y /= wl.ch; - - return LIMIT(y, 0, term.row-1); -} - void getbuttoninfo(void) { @@ -756,6 +725,82 @@ wldrawcursor(void) oldx = curx, oldy = term.c.y; } +void +wlsetsel(char *str, uint32_t serial) +{ + free(sel.primary); + sel.primary = str; + + if (str) { + sel.source = wl_data_device_manager_create_data_source(wl.datadevmanager); + wl_data_source_add_listener(sel.source, &datasrclistener, NULL); + wl_data_source_offer(sel.source, "text/plain; charset=utf-8"); + } else { + sel.source = NULL; + } + wl_data_device_set_selection(wl.datadev, sel.source, serial); +} + +static inline void +selwritebuf(char *buf, int len) +{ + char *repl = buf; + + /* + * 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. + */ + while ((repl = memchr(repl, '\n', len))) { + *repl++ = '\r'; + } + + ttysend(buf, len); +} + +void +wlselpaste(void) +{ + int fds[2], len, left; + char buf[BUFSIZ], *str; + + if (wl.seloffer) { + if (IS_SET(MODE_BRCKTPASTE)) + ttywrite("\033[200~", 6); + /* check if we are pasting from ourselves */ + if (sel.source) { + str = sel.primary; + left = strlen(sel.primary); + while (left > 0) { + len = MIN(sizeof buf, left); + memcpy(buf, str, len); + selwritebuf(buf, len); + left -= len; + str += len; + } + } else { + pipe(fds); + wl_data_offer_receive(wl.seloffer, "text/plain", fds[1]); + wl_display_flush(wl.dpy); + close(fds[1]); + while ((len = read(fds[0], buf, sizeof buf)) > 0) { + selwritebuf(buf, len); + } + close(fds[0]); + } + if (IS_SET(MODE_BRCKTPASTE)) + ttywrite("\033[201~", 6); + } +} + +void +selcopy(uint32_t serial) +{ + wlsetsel(getsel(), serial); +} + /* Rendering stuff */ @@ -781,9 +826,78 @@ wlsettitle(char *title) } void -wlresettitle(void) +draw(void) +{ + int y, y0; + + for (y = 0; y <= term.bot; ++y) { + if (!term.dirty[y]) + continue; + for (y0 = y; y <= term.bot && term.dirty[y]; ++y); + wl_surface_damage(wl.surface, 0, borderpx + y0 * wl.ch, + wl.w, (y - y0) * wl.ch); + } + + wld_set_target_buffer(wld.renderer, wld.buffer); + drawregion(0, 0, term.col, term.row); + wl.framecb = wl_surface_frame(wl.surface); + wl_callback_add_listener(wl.framecb, &framelistener, NULL); + wld_flush(wld.renderer); + wl_surface_attach(wl.surface, wl.buffer, 0, 0); + wl_surface_commit(wl.surface); + /* need to wait to destroy the old buffer until we commit the new + * buffer */ + if (wld.oldbuffer) { + wld_buffer_unreference(wld.oldbuffer); + wld.oldbuffer = 0; + } + needdraw = false; +} + +void +drawregion(int x1, int y1, int x2, int y2) +{ + int ic, ib, x, y, ox; + Glyph base, new; + char buf[DRAW_BUF_SIZ]; + int ena_sel = sel.ob.x != -1 && sel.alt == IS_SET(MODE_ALTSCREEN); + + for (y = y1; y < y2; y++) { + if (!term.dirty[y]) + continue; + + term.dirty[y] = 0; + base = term.line[y][0]; + ic = ib = ox = 0; + for (x = x1; x < x2; x++) { + new = term.line[y][x]; + if (new.mode == ATTR_WDUMMY) + continue; + if (ena_sel && selected(x, y)) + new.mode ^= ATTR_REVERSE; + if (ib > 0 && (ATTRCMP(base, new) + || ib >= DRAW_BUF_SIZ-UTF_SIZ)) { + wldraws(buf, base, ox, y, ic, ib); + ic = ib = 0; + } + if (ib == 0) { + ox = x; + base = new; + } + + ib += utf8encode(new.u, buf+ib); + ic += (new.mode & ATTR_WIDE)? 2 : 1; + } + if (ib > 0) + wldraws(buf, base, ox, y, ic, ib); + } + wldrawcursor(); +} + +void +wlseturgency(int add) { - wlsettitle(opt_title ? opt_title : "st-wl"); + /* XXX: no urgency equivalent yet in wayland */ } void @@ -1369,6 +1483,83 @@ regglobalremove(void *data, struct wl_registry *registry, uint32_t name) { } +void +datadevoffer(void *data, struct wl_data_device *datadev, + struct wl_data_offer *offer) +{ + wl_data_offer_add_listener(offer, &dataofferlistener, NULL); +} + +void +datadeventer(void *data, struct wl_data_device *datadev, uint32_t serial, + struct wl_surface *surf, wl_fixed_t x, wl_fixed_t y, + struct wl_data_offer *offer) +{ +} + +void +datadevleave(void *data, struct wl_data_device *datadev) +{ +} + +void +datadevmotion(void *data, struct wl_data_device *datadev, uint32_t time, + wl_fixed_t x, wl_fixed_t y) +{ +} + +void +datadevdrop(void *data, struct wl_data_device *datadev) +{ +} + +void +datadevselection(void *data, struct wl_data_device *datadev, + struct wl_data_offer *offer) +{ + if (offer && (uintptr_t) wl_data_offer_get_user_data(offer) == 1) + wl.seloffer = offer; + else + wl.seloffer = NULL; +} + +void +dataofferoffer(void *data, struct wl_data_offer *offer, const char *mimetype) +{ + /* mark the offer as usable if it supports plain text */ + if (strncmp(mimetype, "text/plain", 10) == 0) + wl_data_offer_set_user_data(offer, (void *)(uintptr_t) 1); +} + +void +datasrctarget(void *data, struct wl_data_source *source, const char *mimetype) +{ +} + +void +datasrcsend(void *data, struct wl_data_source *source, const char *mimetype, + int32_t fd) +{ + char *buf = sel.primary; + int len = strlen(sel.primary); + ssize_t ret; + while ((ret = write(fd, buf, MIN(len, BUFSIZ))) > 0) { + len -= ret; + buf += ret; + } + close(fd); +} + +void +datasrccancelled(void *data, struct wl_data_source *source) +{ + if (sel.source == source) { + sel.source = NULL; + selclear(); + } + wl_data_source_destroy(source); +} + void wlinit(void) { From a905bde0ac9b0e72810e005e30db4a12849e599b Mon Sep 17 00:00:00 2001 From: ian <42294085+ianbeyst@users.noreply.github.com> Date: Thu, 13 Jun 2019 15:07:59 +0200 Subject: [PATCH 118/129] cleaned up st-wl.h, added win.h, some other boilerplate work --- st-wl.c | 46 +++---- st-wl.h | 367 +++++++++++++++++++++++--------------------------------- win.h | 32 +++++ wl.c | 212 +++++++++++++++++++------------- 4 files changed, 331 insertions(+), 326 deletions(-) create mode 100644 win.h diff --git a/st-wl.c b/st-wl.c index bde4a38..213826f 100644 --- a/st-wl.c +++ b/st-wl.c @@ -31,15 +31,9 @@ /* Wayland */ #include -//#include -//#include "xdg-shell-client-protocol.h" -//#include -//#include - -//#include "arg.h" char *argv0; - +#include "win.h" #include "st-wl.h" #if defined(__linux) @@ -52,7 +46,7 @@ char *argv0; /* Arbitrary sizes */ #define UTF_INVALID 0xFFFD -#define ESC_BUF_SIZ (128*UTF_SIZ) +// #define ESC_BUF_SIZ (128*UTF_SIZ) // Required in st-wl.h #define ESC_ARG_SIZ 16 #define STR_BUF_SIZ ESC_BUF_SIZ #define STR_ARG_SIZ ESC_ARG_SIZ @@ -135,7 +129,7 @@ typedef struct { static void clipcopy(const Arg *); static void clippaste(const Arg *); static void numlock(const Arg *); -// static void selpaste(const Arg *); // Used in wl.c, defined in st-wl.h +static void selpaste(const Arg *); static void wlzoom(const Arg *); static void wlzoomabs(const Arg *); static void wlzoomreset(const Arg *); @@ -208,7 +202,7 @@ static ssize_t xwrite(int, const char *, size_t); static void *xrealloc(void *, size_t); /* Globals */ -Wayland wl; // TermWindow win +TermWindow win; Term term; Selection sel; int cmdfd; @@ -395,7 +389,7 @@ int x2col(int x) { x -= borderpx; - x /= wl.cw; + x /= win.cw; return LIMIT(x, 0, term.col-1); } @@ -404,7 +398,7 @@ int y2row(int y) { y -= borderpx; - y /= wl.ch; + y /= win.ch; return LIMIT(y, 0, term.row-1); } @@ -665,7 +659,7 @@ execsh(void) setenv("SHELL", sh, 1); setenv("HOME", pw->pw_dir, 1); setenv("TERM", termname, 1); - // xsetenv(); + // xsetenv(); // Removed in wayland version signal(SIGCHLD, SIG_DFL); signal(SIGHUP, SIG_DFL); @@ -904,8 +898,8 @@ ttyresize(void) w.ws_row = term.row; w.ws_col = term.col; - w.ws_xpixel = wl.tw; - w.ws_ypixel = wl.th; + w.ws_xpixel = win.tw; + w.ws_ypixel = win.th; if (ioctl(cmdfd, TIOCSWINSZ, &w) < 0) fprintf(stderr, "Couldn't set window size: %s\n", strerror(errno)); } @@ -1480,22 +1474,22 @@ tsetmode(int priv, int set, int *args, int narg) MODBIT(term.mode, !set, MODE_HIDE); break; case 9: /* X10 mouse compatibility mode */ - // xsetpointermotion(0); + // xsetpointermotion(0); // Removed in wayland version MODBIT(term.mode, 0, MODE_MOUSE); MODBIT(term.mode, set, MODE_MOUSEX10); break; case 1000: /* 1000: report button press */ - // xsetpointermotion(0); + // xsetpointermotion(0); // Removed in wayland version MODBIT(term.mode, 0, MODE_MOUSE); MODBIT(term.mode, set, MODE_MOUSEBTN); break; case 1002: /* 1002: report motion on button press */ - // xsetpointermotion(0); + // xsetpointermotion(0); // Removed in wayland version MODBIT(term.mode, 0, MODE_MOUSE); MODBIT(term.mode, set, MODE_MOUSEMOTION); break; case 1003: /* 1003: enable all mouse motions */ - // xsetpointermotion(0); + // xsetpointermotion(0); // Removed in wayland version MODBIT(term.mode, 0, MODE_MOUSE); MODBIT(term.mode, set, MODE_MOUSEMANY); break; @@ -1775,7 +1769,7 @@ csihandle(void) if (!BETWEEN(csiescseq.arg[0], 0, 6)) { goto unknown; } - wl.cursor = csiescseq.arg[0]; + win.cursor = csiescseq.arg[0]; break; default: goto unknown; @@ -2132,7 +2126,7 @@ tcontrolcode(uchar ascii) /* backwards compatibility to xterm */ strhandle(); } else { - if (!(wl.state & WIN_FOCUSED)) + if (!(win.state & WIN_FOCUSED)) wlseturgency(1); // if (bellvolume) // XXX: No bell on wayland // XkbBell(xw.dpy, xw.win, bellvolume, (Atom)NULL); @@ -2475,7 +2469,7 @@ tresize(int col, int row) free(term.alt[i]); } - /* resize to new width */ + /* resize to new width */ // Removed in wayland version // term.specbuf = xrealloc(term.specbuf, col * sizeof(GlyphFontSpec)); /* resize to new height */ @@ -2630,12 +2624,12 @@ cresize(int width, int height) int col, row; if (width != 0) - wl.w = width; + win.w = width; if (height != 0) - wl.h = height; + win.h = height; - col = (wl.w - 2 * borderpx) / wl.cw; - row = (wl.h - 2 * borderpx) / wl.ch; + col = (win.w - 2 * borderpx) / win.cw; + row = (win.h - 2 * borderpx) / win.ch; tresize(col, row); wlresize(col, row); diff --git a/st-wl.h b/st-wl.h index f791170..b41dee5 100644 --- a/st-wl.h +++ b/st-wl.h @@ -1,32 +1,90 @@ +/* See LICENSE for license details. */ /* Arbitrary sizes */ #define UTF_SIZ 4 #define ESC_BUF_SIZ (128*UTF_SIZ) - -#define MOD_MASK_ANY UINT_MAX -#define MOD_MASK_NONE 0 -#define MOD_MASK_CTRL (1<<0) -#define MOD_MASK_ALT (1<<1) -#define MOD_MASK_SHIFT (1<<2) -#define MOD_MASK_LOGO (1<<3) - -#define AXIS_VERTICAL WL_POINTER_AXIS_VERTICAL_SCROLL - - - -/* Macros */ +/* 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 MAX(a, b) ((a) < (b) ? (b) : (a)) -#define MIN(a, b) ((a) < (b) ? (a) : (b)) -#define MODBIT(x, set, bit) ((set) ? ((x) |= (bit)) : ((x) &= ~(bit))) +#define DIVCEIL(n, d) (((n) + ((d) - 1)) / (d)) #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 TRUECOLOR(r,g,b) (1 << 24 | (r) << 16 | (g) << 8 | (b)) +#define IS_TRUECOL(x) (1 << 24 & (x)) + +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 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 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 +}; +enum window_state { + WIN_VISIBLE = 1, + WIN_FOCUSED = 2 +}; -/* type declarations */ typedef unsigned char uchar; typedef unsigned int uint; typedef unsigned long ulong; @@ -50,20 +108,6 @@ typedef struct { char state; } TCursor; -typedef union { - int i; - uint ui; - float f; - const void *v; -} Arg; - -typedef struct { - uint mod; - xkb_keysym_t keysym; - void (*func)(const Arg *); - const Arg arg; -} Shortcut; - /* Internal representation of the screen */ typedef struct { int row; /* nb row */ @@ -71,6 +115,7 @@ typedef struct { Line *line; /* screen */ Line *alt; /* alternate screen */ int *dirty; /* dirtyness of lines */ + //GlyphFontSpec *specbuf; /* font spec buffer used for rendering (deprecated on wayland)*/ TCursor c; /* cursor */ int top; /* top scroll limit */ int bot; /* bottom scroll limit */ @@ -83,62 +128,21 @@ typedef struct { int *tabs; } Term; +/* Purely graphic info */ typedef struct { - struct xkb_context *ctx; - struct xkb_keymap *keymap; - struct xkb_state *state; - xkb_mod_index_t ctrl, alt, shift, logo; - unsigned int mods; -} XKB; - -typedef struct { - uint b; - uint mask; - char *s; -} MouseShortcut; - -typedef struct { - int axis; - int dir; - uint mask; - char s[ESC_BUF_SIZ]; -} Axiskey; - -typedef struct { - struct wl_display *dpy; - struct wl_compositor *cmp; - struct wl_shm *shm; - struct wl_seat *seat; - struct wl_keyboard *keyboard; - struct wl_pointer *pointer; - struct wl_data_device_manager *datadevmanager; - struct wl_data_device *datadev; - struct wl_data_offer *seloffer; - struct wl_surface *surface; - struct wl_buffer *buffer; - struct xdg_wm_base *wm; - struct xdg_surface *xdgsurface; - struct xdg_toplevel *xdgtoplevel; - XKB xkb; - bool configured; - int px, py; /* pointer x and y */ int tw, th; /* tty width and height */ int w, h; /* window width and height */ int ch; /* char height */ int cw; /* char width */ - int vis; char state; /* focus, redraw, visible */ int cursor; /* cursor style */ - struct wl_callback * framecb; -} Wayland; +} TermWindow; typedef struct { - char str[32]; - uint32_t key; - int len; - bool started; - struct timespec last; -} Repeat; + uint b; + uint mask; + char *s; +} MouseShortcut; typedef struct { int mode; @@ -155,155 +159,93 @@ typedef struct { int x, y; } nb, ne, ob, oe; - char *primary; - struct wl_data_source *source; + char *primary; //*clipboard, deprecated on wayland int alt; - uint32_t tclick1, tclick2; + uint32_t tclick1; + uint32_t tclick2; + + struct wl_data_source *source; } Selection; +typedef union { + int i; + uint ui; + float f; + const void *v; +} Arg; + +typedef struct { + uint mod; + xkb_keysym_t keysym; + void (*func)(const Arg *); + const Arg arg; +} Shortcut; + +typedef struct { + int axis; + int dir; + uint mask; + char s[ESC_BUF_SIZ]; +} Axiskey; -/* function declarations */ -void *xmalloc(size_t); +void die(const char *, ...); +void redraw(void); -size_t utf8decode(char *, Rune *, size_t); -size_t utf8encode(Rune, char *); -void usage(void); -char *kmap(xkb_keysym_t, uint); -void cresize(int, int); +int tattrset(int); +void tnew(int, int); +void tsetdirt(int, int); +void tsetdirtattr(int); int match(uint, uint); void ttynew(void); -void ttysend(char *, size_t); size_t ttyread(void); -void ttywrite(const char *, size_t); void ttyresize(void); -void draw(void); -int cmdfd; -void die(const char *, ...); -void redraw(void); +void ttysend(char *, size_t); +void ttywrite(const char *, size_t); -int tattrset(int); -void tsetdirtattr(int); -void tsetdirt(int, int); +void wlresettitle(void); -char *xstrdup(char *); -void tnew(int, int); +char *kmap(xkb_keysym_t, uint); +void cresize(int, int); +void selclear(void); void selinit(void); void selnormalize(void); -void selclear(void); -void selcopy(uint32_t); int selected(int, int); char *getsel(void); int x2col(int); int y2row(int); +size_t utf8decode(char *, Rune *, size_t); +size_t utf8encode(Rune, char *); -void wlsettitle(char *); -void wlresettitle(void); -void wlinit(void); -void wlresize(int, int); -void wlloadcols(void); -int wlsetcolorname(int, const char *); -void wlloadfonts(char *, double); -void wlunloadfonts(void); -void wldrawcursor(void); -void wldraws(char *, Glyph, int, int, int, int); -void wlseturgency(int); -void framedone(void *, struct wl_callback *, uint32_t); -void wlselpaste(void); - - - -/* global variables */ -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 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 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 -}; - -enum window_state { - WIN_VISIBLE = 1, - WIN_FOCUSED = 2 -}; - -pid_t pid; -Wayland wl; -Term term; -Repeat repeat; -Selection sel; - -bool needdraw; - -char **opt_cmd; -char *opt_class; -char *opt_embed; -char *opt_font; -char *opt_io; -char *opt_line; -char *opt_name; -char *opt_title; - -char *usedfont; -double usedfontsize; -double defaultfontsize; +void *xmalloc(size_t); +char *xstrdup(char *); +void usage(void); +/* Globals */ +extern TermWindow win; +extern Term term; +extern Selection sel; +extern int cmdfd; +extern pid_t pid; +extern char **opt_cmd; +extern char *opt_class; +extern char *opt_embed; +extern char *opt_font; +extern char *opt_io; +extern char *opt_line; +extern char *opt_name; +extern char *opt_title; +extern int oldbutton; + +extern char *usedfont; +extern double usedfontsize; +extern double defaultfontsize; + +extern bool needdraw; /* config.h globals */ extern char font[]; @@ -312,18 +254,14 @@ extern float cwscale; extern float chscale; extern unsigned int doubleclicktimeout; extern unsigned int tripleclicktimeout; -extern unsigned int keyrepeatdelay; -extern unsigned int keyrepeatinterval; extern int allowaltscreen; extern unsigned int xfps; extern unsigned int actionfps; extern unsigned int cursorthickness; extern unsigned int blinktimeout; extern char termname[]; -extern unsigned int tabsspaces; extern const char *colorname[]; extern size_t colornamelen; -extern size_t maxcolornamelen; extern unsigned int defaultfg; extern unsigned int defaultbg; extern unsigned int defaultcs; @@ -336,19 +274,20 @@ extern unsigned int mousefg; extern unsigned int mousebg; extern unsigned int defaultattr; extern MouseShortcut mshortcuts[]; -extern Axiskey ashortcuts[]; -extern size_t ashortcutslen; extern size_t mshortcutslen; extern Shortcut shortcuts[]; extern size_t shortcutslen; -extern xkb_keysym_t mappedkeys[]; -extern size_t mappedkeyslen; extern uint forceselmod; extern uint selmasks[]; extern size_t selmaskslen; extern char ascii_printable[]; + +extern unsigned int keyrepeatdelay; +extern unsigned int keyrepeatinterval; +extern unsigned int tabsspaces; +extern Axiskey ashortcuts[]; +extern size_t ashortcutslen; +extern xkb_keysym_t mappedkeys[]; +extern size_t mappedkeyslen; extern uint ignoremod; extern size_t keylen; - -/* function definitions used in config.h */ -void selpaste(const Arg *); diff --git a/win.h b/win.h new file mode 100644 index 0000000..be435fd --- /dev/null +++ b/win.h @@ -0,0 +1,32 @@ +/* See LICENSE for license details. */ + +/* Key modifiers */ +#define MOD_MASK_ANY UINT_MAX +#define MOD_MASK_NONE 0 +#define MOD_MASK_CTRL (1<<0) +#define MOD_MASK_ALT (1<<1) +#define MOD_MASK_SHIFT (1<<2) +#define MOD_MASK_LOGO (1<<3) + +#define AXIS_VERTICAL WL_POINTER_AXIS_VERTICAL_SCROLL + +void draw(void); +void drawregion(int, int, int, int); +void run(void); + +// void xbell(int); +// void xclipcopy(void); +// void xclippaste(void); +// void xhints(void); +void wlinit(void); +void wlloadcols(void); +int wlsetcolorname(int, const char*); +void wlloadfonts(char *, double); +// void xsetenv(void); +void wlsettitle(char *); +// void xsetpointermotion(int); +void wlseturgency(int); +void wlunloadfonts(void); +void wlresize(int, int); +void wlselpaste(void); +// unsigned long xwinid(void); diff --git a/wl.c b/wl.c index 157733b..7501eab 100644 --- a/wl.c +++ b/wl.c @@ -1,58 +1,86 @@ /* See LICENSE for license details. */ -#include #include -#include -#include -/* for BTN_* definitions */ -#include #include -#include -#include -#include -#include -#include #include #include -#include -#include #include -#include -#include -#include -#include -#include #include #include #include +#include +/* for BTN_* definitions */ +#include +#include +#include +#include + #include #include -#include #include #include -#include +#include +//#include #include #include "arg.h" +#include "win.h" #include "st-wl.h" #include "xdg-shell-client-protocol.h" - +//#include +//#include +//#include +//#include +//#include +//#include +//#include +//#include +//#include +//#include +//#include #define DRAW_BUF_SIZ 20*1024 /* Macros */ -#define DIVCEIL(n, d) (((n) + ((d) - 1)) / (d)) -#define TIMEDIFF(t1, t2) ((t1.tv_sec-t2.tv_sec)*1000 + \ - (t1.tv_nsec-t2.tv_nsec)/1E6) -#define ATTRCMP(a, b) ((a).mode != (b).mode || (a).fg != (b).fg || \ - (a).bg != (b).bg) - -#define IS_TRUECOL(x) (1 << 24 & (x)) - /* Type declarations */ +typedef struct { + struct xkb_context *ctx; + struct xkb_keymap *keymap; + struct xkb_state *state; + xkb_mod_index_t ctrl, alt, shift, logo; + unsigned int mods; +} XKB; + +typedef struct { + struct wl_display *dpy; + struct wl_compositor *cmp; + struct wl_shm *shm; + struct wl_seat *seat; + struct wl_keyboard *keyboard; + struct wl_pointer *pointer; + struct wl_data_device_manager *datadevmanager; + struct wl_data_device *datadev; + struct wl_data_offer *seloffer; + struct wl_surface *surface; + struct wl_buffer *buffer; + struct xdg_wm_base *wm; + struct xdg_surface *xdgsurface; + struct xdg_toplevel *xdgtoplevel; + XKB xkb; + bool configured; + int px, py; /* pointer x and y */ + //int tw, th; /* tty width and height */ + //int w, h; /* window width and height */ + //int ch; /* char height */ + //int cw; /* char width */ + int vis; + //char state; /* focus, redraw, visible */ + //int cursor; /* cursor style */ + struct wl_callback * framecb; +} Wayland; /* Font structure */ typedef struct { @@ -89,11 +117,17 @@ typedef struct { struct wld_buffer *buffer, *oldbuffer; } WLD; +typedef struct { + char str[32]; + uint32_t key; + int len; + bool started; + struct timespec last; +} Repeat; -/* Function declarations */ -static void run(void); +/* Function declarations */ static void kbdkeymap(void *, struct wl_keyboard *, uint32_t, int32_t, uint32_t); static void kbdenter(void *, struct wl_keyboard *, uint32_t, struct wl_surface *, struct wl_array *); @@ -116,7 +150,10 @@ static void ptrbutton(void *, struct wl_pointer *, uint32_t, uint32_t, static void ptraxis(void *, struct wl_pointer *, uint32_t, uint32_t, wl_fixed_t); static void wlloadcursor(void); +static void wldrawcursor(void); + static void wlsetsel(char*, uint32_t); +static void selcopy(uint32_t); @@ -125,7 +162,9 @@ static int wlloadfont(Font *, FcPattern *); static void wlunloadfont(Font *f); static void wldrawglyph(Glyph, int, int); static void wlclear(int, int, int, int); -static void drawregion(int, int, int, int); +static void wldraws(char *, Glyph, int, int, int, int); +static void framedone(void *, struct wl_callback *, uint32_t); + static void regglobal(void *, struct wl_registry *, uint32_t, const char *, @@ -175,9 +214,10 @@ static struct wl_data_source_listener datasrclistener = static struct wl_data_offer_listener dataofferlistener = { dataofferoffer }; static DC dc; +static Wayland wl; static WLD wld; static Cursor cursor; -static int oldbutton = 3; /* button event on startup: 3 = release */ +static Repeat repeat; static int oldx, oldy; @@ -238,7 +278,7 @@ void kbdenter(void *data, struct wl_keyboard *keyboard, uint32_t serial, struct wl_surface *surface, struct wl_array *keys) { - wl.state |= WIN_FOCUSED; + win.state |= WIN_FOCUSED; if (IS_SET(MODE_FOCUS)) ttywrite("\033[I", 3); /* need to redraw the cursor */ @@ -251,7 +291,7 @@ kbdleave(void *data, struct wl_keyboard *keyboard, uint32_t serial, { /* selection offers are invalidated when we lose keyboard focus */ wl.seloffer = NULL; - wl.state &= ~WIN_FOCUSED; + win.state &= ~WIN_FOCUSED; if (IS_SET(MODE_FOCUS)) ttywrite("\033[O", 3); /* need to redraw the cursor */ @@ -532,7 +572,7 @@ ptrbutton(void * data, struct wl_pointer * pointer, uint32_t serial, switch (state) { case WL_POINTER_BUTTON_STATE_RELEASED: if (button == BTN_MIDDLE) { - selpaste(NULL); + wlselpaste(); } else if (button == BTN_LEFT) { if (sel.mode == SEL_READY) { getbuttoninfo(); @@ -643,8 +683,8 @@ wldrawcursor(void) og.mode ^= ATTR_REVERSE; wldrawglyph(og, oldx, oldy); if (oldx != curx || oldy != term.c.y) { - wl_surface_damage(wl.surface, borderpx + oldx * wl.cw, - borderpx + oldy * wl.ch, wl.cw, wl.ch); + wl_surface_damage(wl.surface, borderpx + oldx * win.cw, + borderpx + oldy * win.ch, win.cw, win.ch); } g.u = term.line[term.c.y][term.c.x].u; @@ -676,8 +716,8 @@ wldrawcursor(void) return; /* draw the new one */ - if (wl.state & WIN_FOCUSED) { - switch (wl.cursor) { + if (win.state & WIN_FOCUSED) { + switch (win.cursor) { case 7: /* st-wl extension: snowman */ utf8decode("☃", &g.u, UTF_SIZ); case 0: /* Blinking Block */ @@ -689,39 +729,39 @@ wldrawcursor(void) case 3: /* Blinking Underline */ case 4: /* Steady Underline */ wld_fill_rectangle(wld.renderer, drawcol, - borderpx + curx * wl.cw, - borderpx + (term.c.y + 1) * wl.ch - \ + borderpx + curx * win.cw, + borderpx + (term.c.y + 1) * win.ch - \ cursorthickness, - wl.cw, cursorthickness); + win.cw, cursorthickness); break; case 5: /* Blinking bar */ case 6: /* Steady bar */ wld_fill_rectangle(wld.renderer, drawcol, - borderpx + curx * wl.cw, - borderpx + term.c.y * wl.ch, - cursorthickness, wl.ch); + borderpx + curx * win.cw, + borderpx + term.c.y * win.ch, + cursorthickness, win.ch); break; } } else { wld_fill_rectangle(wld.renderer, drawcol, - borderpx + curx * wl.cw, - borderpx + term.c.y * wl.ch, - wl.cw - 1, 1); + borderpx + curx * win.cw, + borderpx + term.c.y * win.ch, + win.cw - 1, 1); wld_fill_rectangle(wld.renderer, drawcol, - borderpx + curx * wl.cw, - borderpx + term.c.y * wl.ch, - 1, wl.ch - 1); + borderpx + curx * win.cw, + borderpx + term.c.y * win.ch, + 1, win.ch - 1); wld_fill_rectangle(wld.renderer, drawcol, - borderpx + (curx + 1) * wl.cw - 1, - borderpx + term.c.y * wl.ch, - 1, wl.ch - 1); + borderpx + (curx + 1) * win.cw - 1, + borderpx + term.c.y * win.ch, + 1, win.ch - 1); wld_fill_rectangle(wld.renderer, drawcol, - borderpx + curx * wl.cw, - borderpx + (term.c.y + 1) * wl.ch - 1, - wl.cw, 1); + borderpx + curx * win.cw, + borderpx + (term.c.y + 1) * win.ch - 1, + win.cw, 1); } - wl_surface_damage(wl.surface, borderpx + curx * wl.cw, - borderpx + term.c.y * wl.ch, wl.cw, wl.ch); + wl_surface_damage(wl.surface, borderpx + curx * win.cw, + borderpx + term.c.y * win.ch, win.cw, win.ch); oldx = curx, oldy = term.c.y; } @@ -809,11 +849,11 @@ wlresize(int col, int row) { union wld_object object; - wl.tw = MAX(1, col * wl.cw); - wl.th = MAX(1, row * wl.ch); + win.tw = MAX(1, col * win.cw); + win.th = MAX(1, row * win.ch); wld.oldbuffer = wld.buffer; - wld.buffer = wld_create_buffer(wld.ctx, wl.w, wl.h, + wld.buffer = wld_create_buffer(wld.ctx, win.w, win.h, WLD_FORMAT_XRGB8888, 0); wld_export(wld.buffer, WLD_WAYLAND_OBJECT_BUFFER, &object); wl.buffer = object.ptr; @@ -834,8 +874,8 @@ draw(void) if (!term.dirty[y]) continue; for (y0 = y; y <= term.bot && term.dirty[y]; ++y); - wl_surface_damage(wl.surface, 0, borderpx + y0 * wl.ch, - wl.w, (y - y0) * wl.ch); + wl_surface_damage(wl.surface, 0, borderpx + y0 * win.ch, + win.w, (y - y0) * win.ch); } wld_set_target_buffer(wld.renderer, wld.buffer); @@ -904,15 +944,15 @@ void surfenter(void *data, struct wl_surface *surface, struct wl_output *output) { wl.vis++; - if (!(wl.state & WIN_VISIBLE)) - wl.state |= WIN_VISIBLE; + if (!(win.state & WIN_VISIBLE)) + win.state |= WIN_VISIBLE; } void surfleave(void *data, struct wl_surface *surface, struct wl_output *output) { if (--wl.vis == 0) - wl.state &= ~WIN_VISIBLE; + win.state &= ~WIN_VISIBLE; } void @@ -920,7 +960,7 @@ framedone(void *data, struct wl_callback *callback, uint32_t msecs) { wl_callback_destroy(callback); wl.framecb = NULL; - if (needdraw && wl.state & WIN_VISIBLE) { + if (needdraw && win.state & WIN_VISIBLE) { draw(); } } @@ -946,7 +986,7 @@ void xdgtoplevelconfigure(void *data, struct xdg_toplevel *toplevel, int32_t w, int32_t h, struct wl_array *states) { - if (w == wl.w && h == wl.h) + if (w == win.w && h == win.h) return; cresize(w, h); if (wl.configured) @@ -1152,8 +1192,8 @@ wlloadfonts(char *fontstr, double fontsize) } /* Setting character width and height. */ - wl.cw = ceilf(dc.font.width * cwscale); - wl.ch = ceilf(dc.font.height * chscale); + win.cw = ceilf(dc.font.width * cwscale); + win.ch = ceilf(dc.font.height * chscale); FcPatternDel(pattern, FC_SLANT); FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ITALIC); @@ -1203,8 +1243,8 @@ wlunloadfonts(void) void wldraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) { - int winx = borderpx + x * wl.cw, winy = borderpx + y * wl.ch, - width = charlen * wl.cw, xp, i; + int winx = borderpx + x * win.cw, winy = borderpx + y * win.ch, + width = charlen * win.cw, xp, i; int frcflags, charexists; int u8fl, u8fblen, u8cblen, doesexist; char *u8c, *u8fs; @@ -1302,19 +1342,19 @@ wldraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) /* Intelligent cleaning up of the borders. */ if (x == 0) { wlclear(0, (y == 0)? 0 : winy, borderpx, - ((y >= term.row-1)? wl.h : (winy + wl.ch))); + ((y >= term.row-1)? win.h : (winy + win.ch))); } if (x + charlen >= term.col) { - wlclear(winx + width, (y == 0)? 0 : winy, wl.w, - ((y >= term.row-1)? wl.h : (winy + wl.ch))); + wlclear(winx + width, (y == 0)? 0 : winy, win.w, + ((y >= term.row-1)? win.h : (winy + win.ch))); } if (y == 0) wlclear(winx, 0, winx + width, borderpx); if (y == term.row-1) - wlclear(winx, winy + wl.ch, winx + width, wl.h); + wlclear(winx, winy + win.ch, winx + width, win.h); /* Clean up the region we want to draw to. */ - wld_fill_rectangle(wld.renderer, bg, winx, winy, width, wl.ch); + wld_fill_rectangle(wld.renderer, bg, winx, winy, width, win.ch); for (xp = winx; bytelen > 0;) { /* @@ -1326,7 +1366,7 @@ wldraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) u8fs = s; u8fblen = 0; u8fl = 0; - oneatatime = font->width != wl.cw; + oneatatime = font->width != win.cw; for (;;) { u8c = s; u8cblen = utf8decode(s, &unicodep, UTF_SIZ); @@ -1346,7 +1386,7 @@ wldraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) font->match, fg, xp, winy + font->ascent, u8fs, u8fblen, NULL); - xp += wl.cw * u8fl; + xp += win.cw * u8fl; } break; } @@ -1423,7 +1463,7 @@ wldraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) xp, winy + frc[i].font->ascent, u8c, u8cblen, NULL); - xp += wl.cw * wcwidth(unicodep); + xp += win.cw * wcwidth(unicodep); } if (base.mode & ATTR_UNDERLINE) { @@ -1604,8 +1644,8 @@ wlinit(void) wlloadcursor(); wl.vis = 0; - wl.h = 2 * borderpx + term.row * wl.ch; - wl.w = 2 * borderpx + term.col * wl.cw; + win.h = 2 * borderpx + term.row * win.ch; + win.w = 2 * borderpx + term.col * win.cw; wl.surface = wl_compositor_create_surface(wl.cmp); wl_surface_add_listener(wl.surface, &surflistener, NULL); @@ -1633,7 +1673,7 @@ run(void) /* Look for initial configure. */ wl_display_roundtrip(wl.dpy); if (!wl.configured) - cresize(wl.w, wl.h); + cresize(win.w, win.h); ttynew(); ttyresize(); draw(); @@ -1693,7 +1733,7 @@ run(void) } } - if (needdraw && wl.state & WIN_VISIBLE) { + if (needdraw && win.state & WIN_VISIBLE) { if (!wl.framecb) { draw(); } @@ -1715,7 +1755,7 @@ run(void) int main(int argc, char *argv[]) { - wl.cursor = cursorshape; + win.cursor = cursorshape; ARGBEGIN { case 'a': From fcb79e6a95f2f09f17dd89ef9c5e24cbdb8be2a9 Mon Sep 17 00:00:00 2001 From: ian <42294085+ianbeyst@users.noreply.github.com> Date: Thu, 13 Jun 2019 17:02:14 +0200 Subject: [PATCH 119/129] Cleaned up wl.c --- st-wl.h | 2 +- wl.c | 901 +++++++++++++++++++++++++++----------------------------- 2 files changed, 432 insertions(+), 471 deletions(-) diff --git a/st-wl.h b/st-wl.h index b41dee5..fe93cbe 100644 --- a/st-wl.h +++ b/st-wl.h @@ -1,4 +1,4 @@ -/* See LICENSE for license details. */ + /* Arbitrary sizes */ #define UTF_SIZ 4 diff --git a/wl.c b/wl.c index 7501eab..3ce7970 100644 --- a/wl.c +++ b/wl.c @@ -19,7 +19,6 @@ #include #include #include -//#include #include #include "arg.h" @@ -27,25 +26,8 @@ #include "st-wl.h" #include "xdg-shell-client-protocol.h" -//#include -//#include -//#include -//#include -//#include -//#include -//#include -//#include -//#include -//#include -//#include - #define DRAW_BUF_SIZ 20*1024 -/* Macros */ - - - -/* Type declarations */ typedef struct { struct xkb_context *ctx; struct xkb_keymap *keymap; @@ -72,17 +54,10 @@ typedef struct { XKB xkb; bool configured; int px, py; /* pointer x and y */ - //int tw, th; /* tty width and height */ - //int w, h; /* window width and height */ - //int ch; /* char height */ - //int cw; /* char width */ int vis; - //char state; /* focus, redraw, visible */ - //int cursor; /* cursor style */ struct wl_callback * framecb; } Wayland; -/* Font structure */ typedef struct { int height; int width; @@ -125,59 +100,60 @@ typedef struct { struct timespec last; } Repeat; - - -/* Function declarations */ -static void kbdkeymap(void *, struct wl_keyboard *, uint32_t, int32_t, uint32_t); -static void kbdenter(void *, struct wl_keyboard *, uint32_t, - struct wl_surface *, struct wl_array *); -static void kbdleave(void *, struct wl_keyboard *, uint32_t, - struct wl_surface *); -static void kbdkey(void *, struct wl_keyboard *, uint32_t, uint32_t, uint32_t, - uint32_t); -static void kbdmodifiers(void *, struct wl_keyboard *, uint32_t, uint32_t, - uint32_t, uint32_t, uint32_t); -static void kbdrepeatinfo(void *, struct wl_keyboard *, int32_t, int32_t); - -static void ptrenter(void *, struct wl_pointer *, uint32_t, struct wl_surface *, - wl_fixed_t, wl_fixed_t); +static void getbuttoninfo(void); +static void wlmousereport(int, bool, int, int); +static void wlmousereportbutton(uint32_t, uint32_t); +static void wlmousereportmotion(wl_fixed_t, wl_fixed_t); +static void wlmousereportaxis(uint32_t, wl_fixed_t); +static void ptrenter(void *, struct wl_pointer *, uint32_t, + struct wl_surface *, wl_fixed_t, wl_fixed_t); static void ptrleave(void *, struct wl_pointer *, uint32_t, - struct wl_surface *); + struct wl_surface *); static void ptrmotion(void *, struct wl_pointer *, uint32_t, - wl_fixed_t, wl_fixed_t); + wl_fixed_t, wl_fixed_t); static void ptrbutton(void *, struct wl_pointer *, uint32_t, uint32_t, - uint32_t, uint32_t); + uint32_t, uint32_t); static void ptraxis(void *, struct wl_pointer *, uint32_t, uint32_t, - wl_fixed_t); -static void wlloadcursor(void); -static void wldrawcursor(void); - + wl_fixed_t); static void wlsetsel(char*, uint32_t); +static inline void selwritebuf(char *, int); static void selcopy(uint32_t); +/* Keyboard stuff */ +static void kbdkeymap(void *, struct wl_keyboard *, uint32_t, int32_t, + uint32_t); +static void kbdenter(void *, struct wl_keyboard *, uint32_t, + struct wl_surface *, struct wl_array *); +static void kbdleave(void *, struct wl_keyboard *, uint32_t, + struct wl_surface *); +static void kbdkey(void *, struct wl_keyboard *, uint32_t, uint32_t, uint32_t, + uint32_t); +static void kbdmodifiers(void *, struct wl_keyboard *, uint32_t, uint32_t, + uint32_t, uint32_t, uint32_t); +static void kbdrepeatinfo(void *, struct wl_keyboard *, int32_t, int32_t); +static void surfenter(void *, struct wl_surface *, struct wl_output *); +static void surfleave(void *, struct wl_surface *, struct wl_output *); +static void framedone(void *, struct wl_callback *, uint32_t); +static void xdgsurfconfigure(void *, struct xdg_surface *, uint32_t); +static void xdgtoplevelconfigure(void *, struct xdg_toplevel *, + int32_t, int32_t, struct wl_array *); +static void xdgtoplevelclose(void *, struct xdg_toplevel *); +static void wmping(void *, struct xdg_wm_base *, uint32_t); static inline uchar sixd_to_8bit(int); static int wlloadfont(Font *, FcPattern *); static void wlunloadfont(Font *f); -static void wldrawglyph(Glyph, int, int); + static void wlclear(int, int, int, int); static void wldraws(char *, Glyph, int, int, int, int); -static void framedone(void *, struct wl_callback *, uint32_t); - - +static void wldrawglyph(Glyph, int, int); +static void wlloadcursor(void); +static void wldrawcursor(void); static void regglobal(void *, struct wl_registry *, uint32_t, const char *, uint32_t); static void regglobalremove(void *, struct wl_registry *, uint32_t); -static void surfenter(void *, struct wl_surface *, struct wl_output *); -static void surfleave(void *, struct wl_surface *, struct wl_output *); -static void wmping(void *, struct xdg_wm_base *, uint32_t); -static void xdgsurfconfigure(void *, struct xdg_surface *, uint32_t); -static void xdgtoplevelconfigure(void *, struct xdg_toplevel *, - int32_t, int32_t, struct wl_array *); -static void xdgtoplevelclose(void *, struct xdg_toplevel *); - static void datadevoffer(void *, struct wl_data_device *, struct wl_data_offer *); static void datadeventer(void *, struct wl_data_device *, uint32_t, @@ -190,29 +166,11 @@ static void datadevselection(void *, struct wl_data_device *, struct wl_data_offer *); static void dataofferoffer(void *, struct wl_data_offer *, const char *); static void datasrctarget(void *, struct wl_data_source *, const char *); -static void datasrcsend(void *, struct wl_data_source *, const char *, int32_t); +static void datasrcsend(void *, struct wl_data_source *, const char *, + int32_t); static void datasrccancelled(void *, struct wl_data_source *); - /* Globals */ -static struct wl_callback_listener framelistener = { framedone }; -static struct wl_registry_listener reglistener = { regglobal, regglobalremove }; -static struct wl_surface_listener surflistener = { surfenter, surfleave }; -static struct wl_keyboard_listener kbdlistener = - { kbdkeymap, kbdenter, kbdleave, kbdkey, kbdmodifiers, kbdrepeatinfo }; -static struct wl_pointer_listener ptrlistener = - { ptrenter, ptrleave, ptrmotion, ptrbutton, ptraxis }; -static struct xdg_wm_base_listener wmlistener = { wmping }; -static struct xdg_surface_listener xdgsurflistener = { xdgsurfconfigure }; -static struct xdg_toplevel_listener xdgtoplevellistener = - { xdgtoplevelconfigure, xdgtoplevelclose }; -static struct wl_data_device_listener datadevlistener = - { datadevoffer, datadeventer, datadevleave, datadevmotion, datadevdrop, - datadevselection }; -static struct wl_data_source_listener datasrclistener = - { datasrctarget, datasrcsend, datasrccancelled }; -static struct wl_data_offer_listener dataofferlistener = { dataofferoffer }; - static DC dc; static Wayland wl; static WLD wld; @@ -220,6 +178,23 @@ static Cursor cursor; static Repeat repeat; static int oldx, oldy; +static struct wl_callback_listener framelistener = { framedone }; +static struct wl_registry_listener reglistener = { regglobal, + regglobalremove }; +static struct wl_surface_listener surflistener = { surfenter, surfleave }; +static struct wl_keyboard_listener kbdlistener = { kbdkeymap, kbdenter, + kbdleave, kbdkey, kbdmodifiers, kbdrepeatinfo }; +static struct wl_pointer_listener ptrlistener = { ptrenter, ptrleave, + ptrmotion, ptrbutton, ptraxis }; +static struct xdg_wm_base_listener wmlistener = { wmping }; +static struct xdg_surface_listener xdgsurflistener = { xdgsurfconfigure }; +static struct xdg_toplevel_listener xdgtoplevellistener = { + xdgtoplevelconfigure, xdgtoplevelclose }; +static struct wl_data_device_listener datadevlistener = { datadevoffer, + datadeventer, datadevleave, datadevmotion, datadevdrop, datadevselection }; +static struct wl_data_source_listener datasrclistener = { datasrctarget, + datasrcsend, datasrccancelled }; +static struct wl_data_offer_listener dataofferlistener = { dataofferoffer }; /* Font Ring Cache */ enum { @@ -239,174 +214,6 @@ typedef struct { static Fontcache frc[16]; static int frclen = 0; - - -/* Keyboard stuff */ -void -kbdkeymap(void *data, struct wl_keyboard *keyboard, uint32_t format, int32_t fd, - uint32_t size) -{ - char *string; - - if (format != WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1) { - close(fd); - return; - } - - string = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0); - - if (string == MAP_FAILED) { - close(fd); - return; - } - - wl.xkb.keymap = xkb_keymap_new_from_string(wl.xkb.ctx, string, - XKB_KEYMAP_FORMAT_TEXT_V1, 0); - munmap(string, size); - close(fd); - wl.xkb.state = xkb_state_new(wl.xkb.keymap); - - wl.xkb.ctrl = xkb_keymap_mod_get_index(wl.xkb.keymap, XKB_MOD_NAME_CTRL); - wl.xkb.alt = xkb_keymap_mod_get_index(wl.xkb.keymap, XKB_MOD_NAME_ALT); - wl.xkb.shift = xkb_keymap_mod_get_index(wl.xkb.keymap, XKB_MOD_NAME_SHIFT); - wl.xkb.logo = xkb_keymap_mod_get_index(wl.xkb.keymap, XKB_MOD_NAME_LOGO); - - wl.xkb.mods = 0; -} - -void -kbdenter(void *data, struct wl_keyboard *keyboard, uint32_t serial, - struct wl_surface *surface, struct wl_array *keys) -{ - win.state |= WIN_FOCUSED; - if (IS_SET(MODE_FOCUS)) - ttywrite("\033[I", 3); - /* need to redraw the cursor */ - needdraw = true; -} - -void -kbdleave(void *data, struct wl_keyboard *keyboard, uint32_t serial, - struct wl_surface *surface) -{ - /* selection offers are invalidated when we lose keyboard focus */ - wl.seloffer = NULL; - win.state &= ~WIN_FOCUSED; - if (IS_SET(MODE_FOCUS)) - ttywrite("\033[O", 3); - /* need to redraw the cursor */ - needdraw = true; - /* disable key repeat */ - repeat.len = 0; -} - -void -kbdkey(void *data, struct wl_keyboard *keyboard, uint32_t serial, uint32_t time, - uint32_t key, uint32_t state) -{ - xkb_keysym_t ksym; - char buf[32], *str; - int len; - Rune c; - Shortcut *bp; - - if (IS_SET(MODE_KBDLOCK)) - return; - - if (state == WL_KEYBOARD_KEY_STATE_RELEASED) { - if (repeat.key == key) - repeat.len = 0; - return; - } - - ksym = xkb_state_key_get_one_sym(wl.xkb.state, key + 8); - len = xkb_keysym_to_utf8(ksym, buf, sizeof buf); - if (len > 0) - --len; - - /* 1. shortcuts */ - for (bp = shortcuts; bp < shortcuts + shortcutslen; bp++) { - if (ksym == bp->keysym && match(bp->mod, wl.xkb.mods)) { - bp->func(&(bp->arg)); - return; - } - } - - /* 2. custom keys from config.h */ - if ((str = kmap(ksym, wl.xkb.mods))) { - len = strlen(str); - goto send; - } - - /* 3. composed string from input method */ - if (len == 0) - return; - if (len == 1 && wl.xkb.mods & MOD_MASK_ALT) { - 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; - } - } - /* convert character to control character */ - else if (len == 1 && wl.xkb.mods & MOD_MASK_CTRL) { - if ((*buf >= '@' && *buf < '\177') || *buf == ' ') - *buf &= 0x1F; - else if (*buf == '2') *buf = '\000'; - else if (*buf >= '3' && *buf <= '7') - *buf -= ('3' - '\033'); - else if (*buf == '8') *buf = '\177'; - else if (*buf == '/') *buf = '_' & 0x1F; - } - - str = buf; - -send: - memcpy(repeat.str, str, len); - repeat.key = key; - repeat.len = len; - repeat.started = false; - clock_gettime(CLOCK_MONOTONIC, &repeat.last); - ttysend(str, len); -} - -void -kbdmodifiers(void *data, struct wl_keyboard *keyboard, uint32_t serial, - uint32_t dep, uint32_t lat, uint32_t lck, uint32_t group) -{ - xkb_mod_mask_t mod_mask; - - xkb_state_update_mask(wl.xkb.state, dep, lat, lck, group, 0, 0); - - mod_mask = xkb_state_serialize_mods(wl.xkb.state, XKB_STATE_MODS_EFFECTIVE); - wl.xkb.mods = 0; - - if (mod_mask & (1 << wl.xkb.ctrl)) - wl.xkb.mods |= MOD_MASK_CTRL; - if (mod_mask & (1 << wl.xkb.alt)) - wl.xkb.mods |= MOD_MASK_ALT; - if (mod_mask & (1 << wl.xkb.shift)) - wl.xkb.mods |= MOD_MASK_SHIFT; - if (mod_mask & (1 << wl.xkb.logo)) - wl.xkb.mods |= MOD_MASK_LOGO; -} - -void -kbdrepeatinfo(void *data, struct wl_keyboard *keyboard, int32_t rate, - int32_t delay) -{ - keyrepeatdelay = delay; - keyrepeatinterval = 1000 / rate; -} - - - -/* Mouse stuff */ void getbuttoninfo(void) { @@ -644,147 +451,26 @@ ptraxis(void * data, struct wl_pointer * pointer, uint32_t time, uint32_t axis, } } -static void wlloadcursor(void) +void +wlsetsel(char *str, uint32_t serial) { - char *names[] = { mouseshape, "xterm", "ibeam", "text" }; - int i; - - cursor.theme = wl_cursor_theme_load(NULL, 32, wl.shm); - - for (i = 0; !cursor.cursor && i < LEN(names); i++) - cursor.cursor = wl_cursor_theme_get_cursor(cursor.theme, names[i]); + free(sel.primary); + sel.primary = str; - cursor.surface = wl_compositor_create_surface(wl.cmp); + if (str) { + sel.source = wl_data_device_manager_create_data_source(wl.datadevmanager); + wl_data_source_add_listener(sel.source, &datasrclistener, NULL); + wl_data_source_offer(sel.source, "text/plain; charset=utf-8"); + } else { + sel.source = NULL; + } + wl_data_device_set_selection(wl.datadev, sel.source, serial); } void -wldrawcursor(void) +selwritebuf(char *buf, int len) { - 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); - uint32_t 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; - wldrawglyph(og, oldx, oldy); - if (oldx != curx || oldy != term.c.y) { - wl_surface_damage(wl.surface, borderpx + oldx * win.cw, - borderpx + oldy * win.ch, win.cw, win.ch); - } - - 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 (win.state & WIN_FOCUSED) { - switch (win.cursor) { - case 7: /* st-wl 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; - wldrawglyph(g, term.c.x, term.c.y); - break; - case 3: /* Blinking Underline */ - case 4: /* Steady Underline */ - wld_fill_rectangle(wld.renderer, drawcol, - borderpx + curx * win.cw, - borderpx + (term.c.y + 1) * win.ch - \ - cursorthickness, - win.cw, cursorthickness); - break; - case 5: /* Blinking bar */ - case 6: /* Steady bar */ - wld_fill_rectangle(wld.renderer, drawcol, - borderpx + curx * win.cw, - borderpx + term.c.y * win.ch, - cursorthickness, win.ch); - break; - } - } else { - wld_fill_rectangle(wld.renderer, drawcol, - borderpx + curx * win.cw, - borderpx + term.c.y * win.ch, - win.cw - 1, 1); - wld_fill_rectangle(wld.renderer, drawcol, - borderpx + curx * win.cw, - borderpx + term.c.y * win.ch, - 1, win.ch - 1); - wld_fill_rectangle(wld.renderer, drawcol, - borderpx + (curx + 1) * win.cw - 1, - borderpx + term.c.y * win.ch, - 1, win.ch - 1); - wld_fill_rectangle(wld.renderer, drawcol, - borderpx + curx * win.cw, - borderpx + (term.c.y + 1) * win.ch - 1, - win.cw, 1); - } - wl_surface_damage(wl.surface, borderpx + curx * win.cw, - borderpx + term.c.y * win.ch, win.cw, win.ch); - oldx = curx, oldy = term.c.y; -} - -void -wlsetsel(char *str, uint32_t serial) -{ - free(sel.primary); - sel.primary = str; - - if (str) { - sel.source = wl_data_device_manager_create_data_source(wl.datadevmanager); - wl_data_source_add_listener(sel.source, &datasrclistener, NULL); - wl_data_source_offer(sel.source, "text/plain; charset=utf-8"); - } else { - sel.source = NULL; - } - wl_data_device_set_selection(wl.datadev, sel.source, serial); -} - -static inline void -selwritebuf(char *buf, int len) -{ - char *repl = buf; + char *repl = buf; /* * As seen in getsel: @@ -841,97 +527,186 @@ selcopy(uint32_t serial) wlsetsel(getsel(), serial); } - - -/* Rendering stuff */ void -wlresize(int col, int row) +kbdkeymap(void *data, struct wl_keyboard *keyboard, uint32_t format, + int32_t fd, uint32_t size) { - union wld_object object; + char *string; - win.tw = MAX(1, col * win.cw); - win.th = MAX(1, row * win.ch); + if (format != WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1) { + close(fd); + return; + } - wld.oldbuffer = wld.buffer; - wld.buffer = wld_create_buffer(wld.ctx, win.w, win.h, - WLD_FORMAT_XRGB8888, 0); - wld_export(wld.buffer, WLD_WAYLAND_OBJECT_BUFFER, &object); - wl.buffer = object.ptr; + string = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0); + + if (string == MAP_FAILED) { + close(fd); + return; + } + + wl.xkb.keymap = xkb_keymap_new_from_string(wl.xkb.ctx, string, + XKB_KEYMAP_FORMAT_TEXT_V1, 0); + munmap(string, size); + close(fd); + wl.xkb.state = xkb_state_new(wl.xkb.keymap); + + wl.xkb.ctrl = xkb_keymap_mod_get_index(wl.xkb.keymap, XKB_MOD_NAME_CTRL); + wl.xkb.alt = xkb_keymap_mod_get_index(wl.xkb.keymap, XKB_MOD_NAME_ALT); + wl.xkb.shift = xkb_keymap_mod_get_index(wl.xkb.keymap, XKB_MOD_NAME_SHIFT); + wl.xkb.logo = xkb_keymap_mod_get_index(wl.xkb.keymap, XKB_MOD_NAME_LOGO); + + wl.xkb.mods = 0; } void -wlsettitle(char *title) +kbdenter(void *data, struct wl_keyboard *keyboard, uint32_t serial, + struct wl_surface *surface, struct wl_array *keys) { - xdg_toplevel_set_title(wl.xdgtoplevel, title); + win.state |= WIN_FOCUSED; + if (IS_SET(MODE_FOCUS)) + ttywrite("\033[I", 3); + /* need to redraw the cursor */ + needdraw = true; } void -draw(void) +kbdleave(void *data, struct wl_keyboard *keyboard, uint32_t serial, + struct wl_surface *surface) { - int y, y0; + /* selection offers are invalidated when we lose keyboard focus */ + wl.seloffer = NULL; + win.state &= ~WIN_FOCUSED; + if (IS_SET(MODE_FOCUS)) + ttywrite("\033[O", 3); + /* need to redraw the cursor */ + needdraw = true; + /* disable key repeat */ + repeat.len = 0; +} - for (y = 0; y <= term.bot; ++y) { - if (!term.dirty[y]) - continue; - for (y0 = y; y <= term.bot && term.dirty[y]; ++y); - wl_surface_damage(wl.surface, 0, borderpx + y0 * win.ch, - win.w, (y - y0) * win.ch); +void +kbdkey(void *data, struct wl_keyboard *keyboard, uint32_t serial, uint32_t time, + uint32_t key, uint32_t state) +{ + xkb_keysym_t ksym; + char buf[32], *str; + int len; + Rune c; + Shortcut *bp; + + if (IS_SET(MODE_KBDLOCK)) + return; + + if (state == WL_KEYBOARD_KEY_STATE_RELEASED) { + if (repeat.key == key) + repeat.len = 0; + return; } - wld_set_target_buffer(wld.renderer, wld.buffer); - drawregion(0, 0, term.col, term.row); - wl.framecb = wl_surface_frame(wl.surface); - wl_callback_add_listener(wl.framecb, &framelistener, NULL); - wld_flush(wld.renderer); - wl_surface_attach(wl.surface, wl.buffer, 0, 0); - wl_surface_commit(wl.surface); - /* need to wait to destroy the old buffer until we commit the new - * buffer */ - if (wld.oldbuffer) { - wld_buffer_unreference(wld.oldbuffer); - wld.oldbuffer = 0; + ksym = xkb_state_key_get_one_sym(wl.xkb.state, key + 8); + len = xkb_keysym_to_utf8(ksym, buf, sizeof buf); + if (len > 0) + --len; + + /* 1. shortcuts */ + for (bp = shortcuts; bp < shortcuts + shortcutslen; bp++) { + if (ksym == bp->keysym && match(bp->mod, wl.xkb.mods)) { + bp->func(&(bp->arg)); + return; + } } - needdraw = false; + + /* 2. custom keys from config.h */ + if ((str = kmap(ksym, wl.xkb.mods))) { + len = strlen(str); + goto send; + } + + /* 3. composed string from input method */ + if (len == 0) + return; + if (len == 1 && wl.xkb.mods & MOD_MASK_ALT) { + 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; + } + } + /* convert character to control character */ + else if (len == 1 && wl.xkb.mods & MOD_MASK_CTRL) { + if ((*buf >= '@' && *buf < '\177') || *buf == ' ') + *buf &= 0x1F; + else if (*buf == '2') *buf = '\000'; + else if (*buf >= '3' && *buf <= '7') + *buf -= ('3' - '\033'); + else if (*buf == '8') *buf = '\177'; + else if (*buf == '/') *buf = '_' & 0x1F; + } + + str = buf; + +send: + memcpy(repeat.str, str, len); + repeat.key = key; + repeat.len = len; + repeat.started = false; + clock_gettime(CLOCK_MONOTONIC, &repeat.last); + ttysend(str, len); +} + +void +kbdmodifiers(void *data, struct wl_keyboard *keyboard, uint32_t serial, + uint32_t dep, uint32_t lat, uint32_t lck, uint32_t group) +{ + xkb_mod_mask_t mod_mask; + + xkb_state_update_mask(wl.xkb.state, dep, lat, lck, group, 0, 0); + + mod_mask = xkb_state_serialize_mods(wl.xkb.state, XKB_STATE_MODS_EFFECTIVE); + wl.xkb.mods = 0; + + if (mod_mask & (1 << wl.xkb.ctrl)) + wl.xkb.mods |= MOD_MASK_CTRL; + if (mod_mask & (1 << wl.xkb.alt)) + wl.xkb.mods |= MOD_MASK_ALT; + if (mod_mask & (1 << wl.xkb.shift)) + wl.xkb.mods |= MOD_MASK_SHIFT; + if (mod_mask & (1 << wl.xkb.logo)) + wl.xkb.mods |= MOD_MASK_LOGO; +} + +void +kbdrepeatinfo(void *data, struct wl_keyboard *keyboard, int32_t rate, + int32_t delay) +{ + keyrepeatdelay = delay; + keyrepeatinterval = 1000 / rate; +} +void +wlresize(int col, int row) +{ + union wld_object object; + + win.tw = MAX(1, col * win.cw); + win.th = MAX(1, row * win.ch); + + wld.oldbuffer = wld.buffer; + wld.buffer = wld_create_buffer(wld.ctx, win.w, win.h, + WLD_FORMAT_XRGB8888, 0); + wld_export(wld.buffer, WLD_WAYLAND_OBJECT_BUFFER, &object); + wl.buffer = object.ptr; } void -drawregion(int x1, int y1, int x2, int y2) +wlsettitle(char *title) { - int ic, ib, x, y, ox; - Glyph base, new; - char buf[DRAW_BUF_SIZ]; - int ena_sel = sel.ob.x != -1 && sel.alt == IS_SET(MODE_ALTSCREEN); - - for (y = y1; y < y2; y++) { - if (!term.dirty[y]) - continue; - - term.dirty[y] = 0; - base = term.line[y][0]; - ic = ib = ox = 0; - for (x = x1; x < x2; x++) { - new = term.line[y][x]; - if (new.mode == ATTR_WDUMMY) - continue; - if (ena_sel && selected(x, y)) - new.mode ^= ATTR_REVERSE; - if (ib > 0 && (ATTRCMP(base, new) - || ib >= DRAW_BUF_SIZ-UTF_SIZ)) { - wldraws(buf, base, ox, y, ic, ib); - ic = ib = 0; - } - if (ib == 0) { - ox = x; - base = new; - } - - ib += utf8encode(new.u, buf+ib); - ic += (new.mode & ATTR_WIDE)? 2 : 1; - } - if (ib > 0) - wldraws(buf, base, ox, y, ic, ib); - } - wldrawcursor(); + xdg_toplevel_set_title(wl.xdgtoplevel, title); } void @@ -965,17 +740,6 @@ framedone(void *data, struct wl_callback *callback, uint32_t msecs) } } -/* - * Absolute coordinates. - */ -void -wlclear(int x1, int y1, int x2, int y2) -{ - uint32_t color = dc.col[IS_SET(MODE_REVERSE) ? defaultfg : defaultbg]; - - wld_fill_rectangle(wld.renderer, color, x1, y1, x2 - x1, y2 - y1); -} - void xdgsurfconfigure(void *data, struct xdg_surface *surf, uint32_t serial) { @@ -1003,9 +767,12 @@ xdgtoplevelclose(void *data, struct xdg_toplevel *toplevel) exit(0); } +void +wmping(void *data, struct xdg_wm_base *wm, uint32_t serial) +{ + xdg_wm_base_pong(wm, serial); +} - -/* Font stuff */ uchar sixd_to_8bit(int x) { @@ -1057,6 +824,7 @@ wlsetcolorname(int x, const char *name) if (!BETWEEN(x, 0, dc.collen)) return 1; + if (!wlloadcolor(x, name, &color)) return 1; @@ -1235,6 +1003,86 @@ wlunloadfonts(void) wlunloadfont(&dc.ibfont); } +void +draw(void) +{ + int y, y0; + + for (y = 0; y <= term.bot; ++y) { + if (!term.dirty[y]) + continue; + for (y0 = y; y <= term.bot && term.dirty[y]; ++y); + wl_surface_damage(wl.surface, 0, borderpx + y0 * win.ch, + win.w, (y - y0) * win.ch); + } + + wld_set_target_buffer(wld.renderer, wld.buffer); + drawregion(0, 0, term.col, term.row); + wl.framecb = wl_surface_frame(wl.surface); + wl_callback_add_listener(wl.framecb, &framelistener, NULL); + wld_flush(wld.renderer); + wl_surface_attach(wl.surface, wl.buffer, 0, 0); + wl_surface_commit(wl.surface); + /* need to wait to destroy the old buffer until we commit the new + * buffer */ + if (wld.oldbuffer) { + wld_buffer_unreference(wld.oldbuffer); + wld.oldbuffer = 0; + } + needdraw = false; +} + +void +drawregion(int x1, int y1, int x2, int y2) +{ + int ic, ib, x, y, ox; + Glyph base, new; + char buf[DRAW_BUF_SIZ]; + int ena_sel = sel.ob.x != -1 && sel.alt == IS_SET(MODE_ALTSCREEN); + + for (y = y1; y < y2; y++) { + if (!term.dirty[y]) + continue; + + term.dirty[y] = 0; + base = term.line[y][0]; + ic = ib = ox = 0; + for (x = x1; x < x2; x++) { + new = term.line[y][x]; + if (new.mode == ATTR_WDUMMY) + continue; + if (ena_sel && selected(x, y)) + new.mode ^= ATTR_REVERSE; + if (ib > 0 && (ATTRCMP(base, new) + || ib >= DRAW_BUF_SIZ-UTF_SIZ)) { + wldraws(buf, base, ox, y, ic, ib); + ic = ib = 0; + } + if (ib == 0) { + ox = x; + base = new; + } + + ib += utf8encode(new.u, buf+ib); + ic += (new.mode & ATTR_WIDE)? 2 : 1; + } + if (ib > 0) + wldraws(buf, base, ox, y, ic, ib); + } + wldrawcursor(); +} + +/* + * Absolute coordinates. + */ +void +wlclear(int x1, int y1, int x2, int y2) +{ + uint32_t color = dc.col[IS_SET(MODE_REVERSE) ? defaultfg : defaultbg]; + + wld_fill_rectangle(wld.renderer, color, x1, y1, x2 - x1, y2 - y1); +} + /* * TODO: Implement something like XftDrawGlyphFontSpec in wld, and then apply a * similar patch to ae1923d27533ff46400d93765e971558201ca1ee @@ -1487,13 +1335,126 @@ wldrawglyph(Glyph g, int x, int y) wldraws(buf, g, x, y, width, len); } +void +wlloadcursor(void) +{ + char *names[] = { mouseshape, "xterm", "ibeam", "text" }; + int i; + + cursor.theme = wl_cursor_theme_load(NULL, 32, wl.shm); + + for (i = 0; !cursor.cursor && i < LEN(names); i++) + cursor.cursor = wl_cursor_theme_get_cursor(cursor.theme, names[i]); + cursor.surface = wl_compositor_create_surface(wl.cmp); +} -/* Technical stuff */ void -wmping(void *data, struct xdg_wm_base *wm, uint32_t serial) +wldrawcursor(void) { - xdg_wm_base_pong(wm, serial); + 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); + uint32_t 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; + wldrawglyph(og, oldx, oldy); + if (oldx != curx || oldy != term.c.y) { + wl_surface_damage(wl.surface, borderpx + oldx * win.cw, + borderpx + oldy * win.ch, win.cw, win.ch); + } + + 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 (win.state & WIN_FOCUSED) { + switch (win.cursor) { + case 7: /* st-wl 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; + wldrawglyph(g, term.c.x, term.c.y); + break; + case 3: /* Blinking Underline */ + case 4: /* Steady Underline */ + wld_fill_rectangle(wld.renderer, drawcol, + borderpx + curx * win.cw, + borderpx + (term.c.y + 1) * win.ch - \ + cursorthickness, + win.cw, cursorthickness); + break; + case 5: /* Blinking bar */ + case 6: /* Steady bar */ + wld_fill_rectangle(wld.renderer, drawcol, + borderpx + curx * win.cw, + borderpx + term.c.y * win.ch, + cursorthickness, win.ch); + break; + } + } else { + wld_fill_rectangle(wld.renderer, drawcol, + borderpx + curx * win.cw, + borderpx + term.c.y * win.ch, + win.cw - 1, 1); + wld_fill_rectangle(wld.renderer, drawcol, + borderpx + curx * win.cw, + borderpx + term.c.y * win.ch, + 1, win.ch - 1); + wld_fill_rectangle(wld.renderer, drawcol, + borderpx + (curx + 1) * win.cw - 1, + borderpx + term.c.y * win.ch, + 1, win.ch - 1); + wld_fill_rectangle(wld.renderer, drawcol, + borderpx + curx * win.cw, + borderpx + (term.c.y + 1) * win.ch - 1, + win.cw, 1); + } + wl_surface_damage(wl.surface, borderpx + curx * win.cw, + borderpx + term.c.y * win.ch, win.cw, win.ch); + oldx = curx, oldy = term.c.y; } void From 972be5f6753df23dd7613ab21eca80e91da5eea5 Mon Sep 17 00:00:00 2001 From: ian <42294085+ianbeyst@users.noreply.github.com> Date: Thu, 13 Jun 2019 17:35:11 +0200 Subject: [PATCH 120/129] Final boilerplate changes to facilitate merging with upstream st --- Makefile | 6 +++--- config.def.h | 39 +++++++++++++++++++++------------------ st-wl.c => st.c | 24 ++++++++++++------------ st-wl.h => st.h | 15 ++++----------- wl.c | 4 ++-- 5 files changed, 42 insertions(+), 46 deletions(-) rename st-wl.c => st.c (99%) rename st-wl.h => st.h (96%) diff --git a/Makefile b/Makefile index 99b91b3..e3989ba 100644 --- a/Makefile +++ b/Makefile @@ -3,7 +3,7 @@ include config.mk -SRC = st-wl.c wl.c xdg-shell-protocol.c +SRC = st.c wl.c xdg-shell-protocol.c OBJ = ${SRC:.c=.o} all: options st-wl @@ -29,8 +29,8 @@ xdg-shell-client-protocol.h: @echo CC $< @${CC} -c ${CFLAGS} $< -st-wl.o: st-wl.h xdg-shell-client-protocol.h -wl.o: st-wl.h xdg-shell-client-protocol.h +st.o: st.h xdg-shell-client-protocol.h +wl.o: st.h xdg-shell-client-protocol.h ${OBJ}: config.h config.mk diff --git a/config.def.h b/config.def.h index 5a25732..6891fc7 100644 --- a/config.def.h +++ b/config.def.h @@ -38,13 +38,13 @@ static char worddelimiters[] = " "; unsigned int doubleclicktimeout = 300; unsigned int tripleclicktimeout = 600; +/* alt screens */ +int allowaltscreen = 1; + /* key repeat timeouts (in milliseconds) */ unsigned int keyrepeatdelay = 500; unsigned int keyrepeatinterval = 25; -/* alt screens */ -int allowaltscreen = 1; - /* * blinking timeout (set to 0 to disable blinking) for the terminal blinking * attribute. @@ -82,7 +82,7 @@ char termname[] = "st-wl-256color"; * * stty tabs */ -unsigned int tabspaces = 8; +static unsigned int tabspaces = 8; /* Terminal colors (16 first used in escape sequence) */ const char *colorname[] = { @@ -169,17 +169,20 @@ Axiskey ashortcuts[] = { #define MODKEY MOD_MASK_ALT Shortcut shortcuts[] = { - /* modifier key function argument */ - { MOD_MASK_ANY, XKB_KEY_Break, sendbreak, {.i = 0} }, - { MOD_MASK_CTRL, XKB_KEY_Print, toggleprinter, {.i = 0} }, - { MOD_MASK_SHIFT, XKB_KEY_Print, printscreen, {.i = 0} }, - { MOD_MASK_ANY, XKB_KEY_Print, printsel, {.i = 0} }, - { MODKEY|MOD_MASK_SHIFT, XKB_KEY_Prior, wlzoom, {.f = +1} }, - { MODKEY|MOD_MASK_SHIFT, XKB_KEY_Next, wlzoom, {.f = -1} }, - { MODKEY|MOD_MASK_SHIFT, XKB_KEY_Home, wlzoomreset, {.f = 0} }, - { MOD_MASK_SHIFT, XKB_KEY_Insert, selpaste, {.i = 0} }, - { MODKEY, XKB_KEY_Num_Lock, numlock, {.i = 0} }, - { MODKEY, XKB_KEY_Control_L, iso14755, {.i = 0} }, + /* modifier key function argument */ + { MOD_MASK_ANY, XKB_KEY_Break, sendbreak, {.i = 0} }, + { MOD_MASK_CTRL, XKB_KEY_Print, toggleprinter, {.i = 0} }, + { MOD_MASK_SHIFT, XKB_KEY_Print, printscreen, {.i = 0} }, + { MOD_MASK_ANY, XKB_KEY_Print, printsel, {.i = 0} }, + { MODKEY|MOD_MASK_SHIFT, XKB_KEY_Prior, zoom, {.f = +1} }, + { MODKEY|MOD_MASK_SHIFT, XKB_KEY_Next, zoom, {.f = -1} }, + { MODKEY|MOD_MASK_SHIFT, XKB_KEY_Home, zoomreset, {.f = 0} }, + { MOD_MASK_SHIFT, XKB_KEY_Insert, selpaste, {.i = 0} }, + { MODKEY|MOD_MASK_SHIFT, XKB_KEY_Insert, clippaste, {.i = 0} }, + { MODKEY|MOD_MASK_SHIFT, XKB_KEY_C, clipcopy, {.i = 0} }, + { MODKEY|MOD_MASK_SHIFT, XKB_KEY_V, clippaste, {.i = 0} }, + { MODKEY, XKB_KEY_Num_Lock, numlock, {.i = 0} }, + { MODKEY, XKB_KEY_Control_L, iso14755, {.i = 0} }, }; /* @@ -211,10 +214,10 @@ Shortcut shortcuts[] = { * If you want keys other than the X11 function keys (0xFD00 - 0xFFFF) * to be mapped below, add them to this array. */ -xkb_keysym_t mappedkeys[] = { -1 }; +static xkb_keysym_t mappedkeys[] = { -1 }; /* State bits to ignore when matching key or button events. */ -uint ignoremod = 0; +static uint ignoremod = 0; /* * Override mouse-select while mask is active (when MODE_MOUSE is set). @@ -227,7 +230,7 @@ uint forceselmod = MOD_MASK_SHIFT; * This is the huge key array which defines all compatibility to the Linux * world. Please decide about changes wisely. */ -Key key[] = { +static Key key[] = { /* keysym mask string appkey appcursor crlf */ { XKB_KEY_KP_Home, MOD_MASK_SHIFT, "\033[2J", 0, -1, 0}, { XKB_KEY_KP_Home, MOD_MASK_SHIFT, "\033[1;2H", 0, +1, 0}, diff --git a/st-wl.c b/st.c similarity index 99% rename from st-wl.c rename to st.c index 213826f..c1b7f31 100644 --- a/st-wl.c +++ b/st.c @@ -34,7 +34,7 @@ char *argv0; #include "win.h" -#include "st-wl.h" +#include "st.h" #if defined(__linux) #include @@ -130,11 +130,11 @@ static void clipcopy(const Arg *); static void clippaste(const Arg *); static void numlock(const Arg *); static void selpaste(const Arg *); -static void wlzoom(const Arg *); -static void wlzoomabs(const Arg *); -static void wlzoomreset(const Arg *); +static void zoom(const Arg *); +static void zoomabs(const Arg *); +static void zoomreset(const Arg *); static void printsel(const Arg *); -static void printscreen(const Arg *); +static void printscreen(const Arg *) ; static void iso14755(const Arg *); static void toggleprinter(const Arg *); static void sendbreak(const Arg *); @@ -2261,7 +2261,7 @@ eschandle(uchar ascii) break; case 'c': /* RIS -- Reset to inital state */ treset(); - wlresettitle(); + resettitle(); wlloadcols(); break; case '=': /* DECPAM -- Application keypad */ @@ -2521,16 +2521,16 @@ tresize(int col, int row) } void -wlzoom(const Arg *arg) +zoom(const Arg *arg) { Arg larg; larg.f = usedfontsize + arg->f; - wlzoomabs(&larg); + zoomabs(&larg); } void -wlzoomabs(const Arg *arg) +zoomabs(const Arg *arg) { wlunloadfonts(); wlloadfonts(usedfont, arg->f); @@ -2543,18 +2543,18 @@ wlzoomabs(const Arg *arg) } void -wlzoomreset(const Arg *arg) +zoomreset(const Arg *arg) { Arg larg; if (defaultfontsize > 0) { larg.f = defaultfontsize; - wlzoomabs(&larg); + zoomabs(&larg); } } void -wlresettitle(void) +resettitle(void) { wlsettitle(opt_title ? opt_title : "st-wl"); } diff --git a/st-wl.h b/st.h similarity index 96% rename from st-wl.h rename to st.h index fe93cbe..7b67546 100644 --- a/st-wl.h +++ b/st.h @@ -1,4 +1,4 @@ - +/* See LICENSE for license details. */ /* Arbitrary sizes */ #define UTF_SIZ 4 @@ -188,8 +188,6 @@ typedef struct { char s[ESC_BUF_SIZ]; } Axiskey; - - void die(const char *, ...); void redraw(void); @@ -204,7 +202,7 @@ void ttyresize(void); void ttysend(char *, size_t); void ttywrite(const char *, size_t); -void wlresettitle(void); +void resettitle(void); char *kmap(xkb_keysym_t, uint); void cresize(int, int); @@ -255,8 +253,8 @@ extern float chscale; extern unsigned int doubleclicktimeout; extern unsigned int tripleclicktimeout; extern int allowaltscreen; -extern unsigned int xfps; -extern unsigned int actionfps; +// extern unsigned int xfps; +// extern unsigned int actionfps; extern unsigned int cursorthickness; extern unsigned int blinktimeout; extern char termname[]; @@ -284,10 +282,5 @@ extern char ascii_printable[]; extern unsigned int keyrepeatdelay; extern unsigned int keyrepeatinterval; -extern unsigned int tabsspaces; extern Axiskey ashortcuts[]; extern size_t ashortcutslen; -extern xkb_keysym_t mappedkeys[]; -extern size_t mappedkeyslen; -extern uint ignoremod; -extern size_t keylen; diff --git a/wl.c b/wl.c index 3ce7970..31a1f76 100644 --- a/wl.c +++ b/wl.c @@ -23,7 +23,7 @@ #include "arg.h" #include "win.h" -#include "st-wl.h" +#include "st.h" #include "xdg-shell-client-protocol.h" #define DRAW_BUF_SIZ 20*1024 @@ -1620,7 +1620,7 @@ wlinit(void) wl_surface_commit(wl.surface); wl.xkb.ctx = xkb_context_new(0); - wlresettitle(); + resettitle(); } void From c282abf2cbf2dc31d93f29753ed6491174d0be86 Mon Sep 17 00:00:00 2001 From: ian <42294085+ianbeyst@users.noreply.github.com> Date: Fri, 14 Jun 2019 11:59:53 +0200 Subject: [PATCH 121/129] moved needdraw into wl.c. Start using upstream st makefile --- Makefile | 68 +++++++++++++++++++++++++------------------------------ config.mk | 26 +++++++++++++-------- st.c | 9 +++----- st.h | 2 -- win.h | 1 + wl.c | 19 ++++++++++++---- 6 files changed, 66 insertions(+), 59 deletions(-) diff --git a/Makefile b/Makefile index e3989ba..8ac213b 100644 --- a/Makefile +++ b/Makefile @@ -1,71 +1,65 @@ # st - simple terminal # See LICENSE file for copyright and license details. +.POSIX: include config.mk SRC = st.c wl.c xdg-shell-protocol.c -OBJ = ${SRC:.c=.o} +OBJ = $(SRC:.c=.o) all: options st-wl options: @echo st-wl 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 xdg-shell-protocol.c: @echo GEN $@ - @wayland-scanner private-code ${XDG_SHELL_PROTO} $@ + @wayland-scanner private-code $(XDG_SHELL_PROTO) $@ xdg-shell-client-protocol.h: @echo GEN $@ - @wayland-scanner client-header ${XDG_SHELL_PROTO} $@ + @wayland-scanner client-header $(XDG_SHELL_PROTO) $@ .c.o: - @echo CC $< - @${CC} -c ${CFLAGS} $< + $(CC) $(STCFLAGS) -c $< -st.o: st.h xdg-shell-client-protocol.h -wl.o: st.h xdg-shell-client-protocol.h +st.o: config.h st.h win.h +wl.o: arg.h config.h st.h win.h xdg-shell-client-protocol.h -${OBJ}: config.h config.mk +$(OBJ): config.h config.mk -st-wl: ${OBJ} - @echo CC -o $@ - @${CC} -o $@ ${OBJ} ${LDFLAGS} +st-wl: $(OBJ) + $(CC) -o $@ $(OBJ) $(STLDFLAGS) clean: - @echo cleaning - @rm -f st-wl ${OBJ} st-wl-${VERSION}.tar.gz xdg-shell-protocol.c xdg-shell-client-protocol.h + rm -f st-wl $(OBJ) st-wl-$(VERSION).tar.gz xdg-shell-* dist: clean - @echo creating dist tarball - @mkdir -p st-wl-${VERSION} - @cp -R LICENSE Makefile README config.mk config.def.h st-wl.info st-wl.1 arg.h ${SRC} st-wl-${VERSION} - @tar -cf st-wl-${VERSION}.tar st-wl-${VERSION} - @gzip st-wl-${VERSION}.tar - @rm -rf st-wl-${VERSION} - -install: all - @echo installing executable file to ${DESTDIR}${PREFIX}/bin - @mkdir -p ${DESTDIR}${PREFIX}/bin - @cp -f st-wl ${DESTDIR}${PREFIX}/bin - @chmod 755 ${DESTDIR}${PREFIX}/bin/st-wl - @echo installing manual page to ${DESTDIR}${MANPREFIX}/man1 - @mkdir -p ${DESTDIR}${MANPREFIX}/man1 - @sed "s/VERSION/${VERSION}/g" < st-wl.1 > ${DESTDIR}${MANPREFIX}/man1/st-wl.1 - @chmod 644 ${DESTDIR}${MANPREFIX}/man1/st-wl.1 + mkdir -p st-wl-$(VERSION) + cp -R FAQ LEGACY TODO LICENSE Makefile README config.mk\ + config.def.h st-wl.info st-wl.1 arg.h st-wl.h win.h $(SRC)\ + st-wl-$(VERSION) + tar -cf - st-wl-$(VERSION) | gzip > st-wl-$(VERSION).tar.gz + rm -rf st-wl-$(VERSION) + +install: st + mkdir -p $(DESTDIR)$(PREFIX)/bin + cp -f st-wl $(DESTDIR)$(PREFIX)/bin + chmod 755 $(DESTDIR)$(PREFIX)/bin/st-wl + mkdir -p $(DESTDIR)$(MANPREFIX)/man1 + sed "s/VERSION/$(VERSION)/g" < st-wl.1 > $(DESTDIR)$(MANPREFIX)/man1/st-wl.1 + chmod 644 $(DESTDIR)$(MANPREFIX)/man1/st-wl.1 + tic -sx st-wl.info @echo Please see the README file regarding the terminfo entry of st-wl. - @tic -sx st-wl.info uninstall: - @echo removing executable file from ${DESTDIR}${PREFIX}/bin - @rm -f ${DESTDIR}${PREFIX}/bin/st-wl - @echo removing manual page from ${DESTDIR}${MANPREFIX}/man1 - @rm -f ${DESTDIR}${MANPREFIX}/man1/st-wl.1 + rm -f $(DESTDIR)$(PREFIX)/bin/st-wl + rm -f $(DESTDIR)$(MANPREFIX)/man1/st-wl.1 .PHONY: all options clean dist install uninstall diff --git a/config.mk b/config.mk index 549a860..1f14b47 100644 --- a/config.mk +++ b/config.mk @@ -1,24 +1,32 @@ # st version -VERSION = 0.7 +VERSION = 0.8.2 # Customize below to fit your system # paths PREFIX = /usr/local -MANPREFIX = ${PREFIX}/share/man +MANPREFIX = $(PREFIX)/share/man +PKG_CONFIG = pkg-config PKGCFG = fontconfig wayland-client wayland-cursor xkbcommon wld -XDG_SHELL_PROTO = `pkg-config --variable=pkgdatadir wayland-protocols`/stable/xdg-shell/xdg-shell.xml +XDG_SHELL_PROTO = `$(PKG_CONFIG) --variable=pkgdatadir wayland-protocols`/stable/xdg-shell/xdg-shell.xml # includes and libs -INCS = -I. -I/usr/include `pkg-config --cflags ${PKGCFG}` -LIBS = -L/usr/lib -lc -lm -lrt -lutil `pkg-config --libs ${PKGCFG}` +INCS = -I. -I/usr/include `$(PKG_CONFIG) --cflags ${PKGCFG}` +LIBS = -L/usr/lib -lc -lm -lrt -lutil `$(PKG_CONFIG) --libs ${PKGCFG}` # flags -CPPFLAGS = -DVERSION=\"${VERSION}\" -D_XOPEN_SOURCE=600 -CFLAGS += -g -std=c99 -pedantic -Wall -Wvariadic-macros -Os ${INCS} ${CPPFLAGS} +CFLAGS += -g -std=c99 -pedantic -Wall -Wvariadic-macros -Os LDFLAGS += -g ${LIBS} +STCPPFLAGS = -DVERSION=\"$(VERSION)\" -D_XOPEN_SOURCE=600 +STCFLAGS = $(INCS) $(STCPPFLAGS) $(CPPFLAGS) $(CFLAGS) +STLDFLAGS = $(LIBS) $(LDFLAGS) -# compiler and linker -# CC = cc +# OpenBSD: +#CPPFLAGS = -DVERSION=\"$(VERSION)\" -D_XOPEN_SOURCE=600 -D_BSD_SOURCE +#LIBS = -L$(X11LIB) -lm -lX11 -lutil -lXft \ +# `pkg-config --libs fontconfig` \ +# `pkg-config --libs freetype2` +# compiler and linker +# CC = c99 diff --git a/st.c b/st.c index c1b7f31..20e8312 100644 --- a/st.c +++ b/st.c @@ -237,9 +237,6 @@ size_t shortcutslen = LEN(shortcuts); size_t selmaskslen = LEN(selmasks); size_t ashortcutslen = LEN(ashortcuts); -/* Wayland stuff */ -bool needdraw = true; - ssize_t xwrite(int fd, const char *s, size_t len) { @@ -804,7 +801,7 @@ ttyread(void) if (buflen > 0) memmove(buf, ptr, buflen); - needdraw = true; + wlneeddraw(); return ret; } @@ -930,7 +927,7 @@ tsetdirt(int top, int bot) for (i = top; i <= bot; i++) term.dirty[i] = 1; - needdraw = true; + wlneeddraw(); } void @@ -2039,7 +2036,7 @@ techo(Rune u) } } tputc(u); - needdraw = true; + wlneeddraw(); } void diff --git a/st.h b/st.h index 7b67546..04724d3 100644 --- a/st.h +++ b/st.h @@ -243,8 +243,6 @@ extern char *usedfont; extern double usedfontsize; extern double defaultfontsize; -extern bool needdraw; - /* config.h globals */ extern char font[]; extern int borderpx; diff --git a/win.h b/win.h index be435fd..228a4b1 100644 --- a/win.h +++ b/win.h @@ -30,3 +30,4 @@ void wlunloadfonts(void); void wlresize(int, int); void wlselpaste(void); // unsigned long xwinid(void); +void wlneeddraw(void); diff --git a/wl.c b/wl.c index 31a1f76..dbb27b2 100644 --- a/wl.c +++ b/wl.c @@ -20,6 +20,7 @@ #include #include #include +#include #include "arg.h" #include "win.h" @@ -56,6 +57,7 @@ typedef struct { int px, py; /* pointer x and y */ int vis; struct wl_callback * framecb; + bool needdraw; } Wayland; typedef struct { @@ -567,7 +569,7 @@ kbdenter(void *data, struct wl_keyboard *keyboard, uint32_t serial, if (IS_SET(MODE_FOCUS)) ttywrite("\033[I", 3); /* need to redraw the cursor */ - needdraw = true; + wlneeddraw(); } void @@ -580,7 +582,7 @@ kbdleave(void *data, struct wl_keyboard *keyboard, uint32_t serial, if (IS_SET(MODE_FOCUS)) ttywrite("\033[O", 3); /* need to redraw the cursor */ - needdraw = true; + wlneeddraw(); /* disable key repeat */ repeat.len = 0; } @@ -735,7 +737,7 @@ framedone(void *data, struct wl_callback *callback, uint32_t msecs) { wl_callback_destroy(callback); wl.framecb = NULL; - if (needdraw && win.state & WIN_VISIBLE) { + if (wl.needdraw && win.state & WIN_VISIBLE) { draw(); } } @@ -1003,6 +1005,12 @@ wlunloadfonts(void) wlunloadfont(&dc.ibfont); } +void +wlneeddraw(void) +{ + wl.needdraw = true; +} + void draw(void) { @@ -1029,7 +1037,7 @@ draw(void) wld_buffer_unreference(wld.oldbuffer); wld.oldbuffer = 0; } - needdraw = false; + wl.needdraw = false; } void @@ -1569,6 +1577,7 @@ wlinit(void) if (!(wl.dpy = wl_display_connect(NULL))) die("Can't open display\n"); + wl.needdraw = true; registry = wl_display_get_registry(wl.dpy); wl_registry_add_listener(registry, ®listener, NULL); wld.ctx = wld_wayland_create_context(wl.dpy, WLD_ANY); @@ -1694,7 +1703,7 @@ run(void) } } - if (needdraw && win.state & WIN_VISIBLE) { + if (wl.needdraw && win.state & WIN_VISIBLE) { if (!wl.framecb) { draw(); } From 0b2b624c6ac2d3ed22832fd7b606c8a41de55f5d Mon Sep 17 00:00:00 2001 From: ian <42294085+ianbeyst@users.noreply.github.com> Date: Fri, 14 Jun 2019 13:41:09 +0200 Subject: [PATCH 122/129] pre-merge changes up until upstream st commit 32d3b1d --- config.def.h | 6 +- st.c | 390 ++++++++++++++++++--------------------------------- st.h | 51 +++---- win.h | 13 +- wl.c | 184 ++++++++++++++++++++++-- 5 files changed, 340 insertions(+), 304 deletions(-) diff --git a/config.def.h b/config.def.h index 6891fc7..fa82aa7 100644 --- a/config.def.h +++ b/config.def.h @@ -214,10 +214,10 @@ Shortcut shortcuts[] = { * If you want keys other than the X11 function keys (0xFD00 - 0xFFFF) * to be mapped below, add them to this array. */ -static xkb_keysym_t mappedkeys[] = { -1 }; +xkb_keysym_t mappedkeys[] = { -1 }; /* State bits to ignore when matching key or button events. */ -static uint ignoremod = 0; +uint ignoremod = 0; /* * Override mouse-select while mask is active (when MODE_MOUSE is set). @@ -230,7 +230,7 @@ uint forceselmod = MOD_MASK_SHIFT; * This is the huge key array which defines all compatibility to the Linux * world. Please decide about changes wisely. */ -static Key key[] = { +Key key[] = { /* keysym mask string appkey appcursor crlf */ { XKB_KEY_KP_Home, MOD_MASK_SHIFT, "\033[2J", 0, -1, 0}, { XKB_KEY_KP_Home, MOD_MASK_SHIFT, "\033[1;2H", 0, +1, 0}, diff --git a/st.c b/st.c index 20e8312..52cc9f9 100644 --- a/st.c +++ b/st.c @@ -32,9 +32,9 @@ /* Wayland */ #include -char *argv0; -#include "win.h" + #include "st.h" +#include "win.h" #if defined(__linux) #include @@ -52,8 +52,7 @@ char *argv0; #define STR_ARG_SIZ ESC_ARG_SIZ /* macros */ -#define NUMMAXLEN(x) ((int)(sizeof(x) * 2.56 + 0.5) + 1) -#define DEFAULT(a, b) (a) = (a) ? (a) : (b) +#define NUMMAXLEN(x) ((int)(sizeof(x) * 2.56 + 0.5) + 1) #define ISCONTROLC0(c) (BETWEEN(c, 0, 0x1f) || (c) == '\177') #define ISCONTROLC1(c) (BETWEEN(c, 0x80, 0x9f)) #define ISCONTROL(c) (ISCONTROLC0(c) || ISCONTROLC1(c)) @@ -115,24 +114,11 @@ typedef struct { int narg; /* nb of args */ } STREscape; -typedef struct { - xkb_keysym_t 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; - /* 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 printsel(const Arg *); static void printscreen(const Arg *) ; static void iso14755(const Arg *); @@ -142,8 +128,8 @@ static void sendbreak(const Arg *); /* config.h for applying patches and the configuration. */ #include "config.h" -static void execsh(void); -static void stty(void); +static void execsh(char **); +static void stty(char **); static void sigchld(int); static void csidump(void); @@ -173,7 +159,6 @@ 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 tsetattr(int *, int); @@ -181,8 +166,8 @@ static void tsetchar(Rune, Glyph *, int, int); static void tsetscroll(int, int); static void tswapscreen(void); 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); @@ -198,8 +183,9 @@ static char utf8encodebyte(Rune, size_t); static char *utf8strchr(char *s, Rune u); static size_t utf8validate(Rune *, size_t); +static char *base64dec(const char *); + static ssize_t xwrite(int, const char *, size_t); -static void *xrealloc(void *, size_t); /* Globals */ TermWindow win; @@ -207,24 +193,12 @@ Term term; Selection sel; int cmdfd; pid_t pid; -char **opt_cmd = NULL; -char *opt_class = NULL; -char *opt_embed = NULL; -char *opt_font = NULL; -char *opt_io = NULL; -char *opt_line = NULL; -char *opt_name = NULL; -char *opt_title = NULL; int oldbutton = 3; /* button event on startup: 3 = release */ static CSIEscape csiescseq; static STREscape strescseq; static int iofd = 1; -char *usedfont = NULL; -double usedfontsize = 0; -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}; @@ -235,6 +209,8 @@ size_t colornamelen = LEN(colorname); size_t mshortcutslen = LEN(mshortcuts); size_t shortcutslen = LEN(shortcuts); size_t selmaskslen = LEN(selmasks); +size_t keyslen = LEN(key); +size_t mappedkeyslen = LEN(mappedkeys); size_t ashortcutslen = LEN(ashortcuts); ssize_t @@ -284,7 +260,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; @@ -370,11 +346,60 @@ 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) { - sel.tclick1 = 0; - sel.tclick2 = 0; + sel.tclick1 = 0; + sel.tclick2 = 0; sel.mode = SEL_IDLE; sel.snap = 0; sel.ob.x = -1; @@ -382,24 +407,6 @@ selinit(void) sel.source = NULL; } -int -x2col(int x) -{ - x -= borderpx; - x /= win.cw; - - return LIMIT(x, 0, term.col-1); -} - -int -y2row(int y) -{ - y -= borderpx; - y /= win.ch; - - return LIMIT(y, 0, term.row-1); -} - int tlinelen(int y) { @@ -624,9 +631,9 @@ die(const char *errstr, ...) } void -execsh(void) +execsh(char **args) { - char **args, *sh, *prog; + char *sh, *prog; const struct passwd *pw; errno = 0; @@ -640,13 +647,13 @@ execsh(void) if ((sh = getenv("SHELL")) == NULL) sh = (pw->pw_shell[0]) ? pw->pw_shell : shell; - 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}; + DEFAULT(args, ((char *[]) {prog, NULL})); unsetenv("COLUMNS"); unsetenv("LINES"); @@ -656,7 +663,6 @@ execsh(void) setenv("SHELL", sh, 1); setenv("HOME", pw->pw_dir, 1); setenv("TERM", termname, 1); - // xsetenv(); // Removed in wayland version signal(SIGCHLD, SIG_DFL); signal(SIGHUP, SIG_DFL); @@ -688,7 +694,7 @@ sigchld(int a) void -stty(void) +stty(char **args) { char cmd[_POSIX_ARG_MAX], **p, *q, *s; size_t n, siz; @@ -698,7 +704,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++ = ' '; @@ -712,26 +718,26 @@ stty(void) } void -ttynew(void) +ttynew(char *line, 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(); + stty(args); return; } @@ -753,7 +759,7 @@ ttynew(void) die("ioctl TIOCSCTTY failed: %s\n", strerror(errno)); close(s); close(m); - execsh(); + execsh(args); break; default: close(s); @@ -768,38 +774,19 @@ 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); wlneeddraw(); return ret; @@ -865,38 +852,20 @@ ttywrite(const char *s, size_t n) 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; - } + if (IS_SET(MODE_ECHO)) + twrite(s, n, 1); } void -ttyresize(void) +ttyresize(int tw, int th) { struct winsize w; w.ws_row = term.row; w.ws_col = term.col; - w.ws_xpixel = win.tw; - w.ws_ypixel = win.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)); } @@ -1824,6 +1793,19 @@ strhandle(void) if (narg > 1) wlsettitle(strescseq.args[1]); return; + case 52: + if (narg > 2) { + char *dec; + + dec = base64dec(strescseq.args[2]); + if (dec) { + setsel(dec); + clipcopy(NULL); + } else { + fprintf(stderr, "erresc: invalid base64\n"); + } + } + return; case 4: /* color set */ if (narg < 3) break; @@ -1923,8 +1905,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; } @@ -2022,23 +2003,6 @@ tputtab(int n) term.c.x = LIMIT(x, 0, term.col-1); } -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); - wlneeddraw(); -} - void tdefutf8(char ascii) { @@ -2123,8 +2087,6 @@ tcontrolcode(uchar ascii) /* backwards compatibility to xterm */ strhandle(); } else { - if (!(win.state & WIN_FOCUSED)) - wlseturgency(1); // if (bellvolume) // XXX: No bell on wayland // XkbBell(xw.dpy, xw.win, bellvolume, (Atom)NULL); } @@ -2432,6 +2394,38 @@ tputc(Rune u) } } +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) { @@ -2466,9 +2460,6 @@ tresize(int col, int row) free(term.alt[i]); } - /* resize to new width */ // Removed in wayland version - // term.specbuf = xrealloc(term.specbuf, col * sizeof(GlyphFontSpec)); - /* resize to new height */ term.line = xrealloc(term.line, row * sizeof(Line)); term.alt = xrealloc(term.alt, row * sizeof(Line)); @@ -2482,7 +2473,7 @@ tresize(int col, int row) } /* 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)); } @@ -2517,56 +2508,17 @@ tresize(int col, int row) term.c = c; } -void -zoom(const Arg *arg) -{ - Arg larg; - - larg.f = usedfontsize + arg->f; - zoomabs(&larg); -} - -void -zoomabs(const Arg *arg) -{ - wlunloadfonts(); - wlloadfonts(usedfont, arg->f); - cresize(0, 0); - ttyresize(); - redraw(); - /* XXX: Should the window size be updated here because wayland doesn't - * have a notion of hints? - * xhints(); */ -} - -void -zoomreset(const Arg *arg) -{ - Arg larg; - - if (defaultfontsize > 0) { - larg.f = defaultfontsize; - zoomabs(&larg); - } -} - void resettitle(void) { - wlsettitle(opt_title ? opt_title : "st-wl"); + wlsettitle(NULL); } void redraw(void) { tfulldirt(); - // draw(); // Removed in wayland branch -} - -int -match(uint mask, uint state) -{ - return mask == MOD_MASK_ANY || mask == (state & ~(ignoremod)); + // draw(); // removed in wayland branch } void @@ -2574,73 +2526,3 @@ numlock(const Arg *dummy) { term.numlock ^= 1; } - -char* -kmap(xkb_keysym_t 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 (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 -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); - wlresize(col, row); -} - -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); -} diff --git a/st.h b/st.h index 04724d3..782c33a 100644 --- a/st.h +++ b/st.h @@ -9,6 +9,7 @@ #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) @@ -80,11 +81,6 @@ enum selection_snap { SNAP_LINE = 2 }; -enum window_state { - WIN_VISIBLE = 1, - WIN_FOCUSED = 2 -}; - typedef unsigned char uchar; typedef unsigned int uint; typedef unsigned long ulong; @@ -115,7 +111,6 @@ typedef struct { Line *line; /* screen */ Line *alt; /* alternate screen */ int *dirty; /* dirtyness of lines */ - //GlyphFontSpec *specbuf; /* font spec buffer used for rendering (deprecated on wayland)*/ TCursor c; /* cursor */ int top; /* top scroll limit */ int bot; /* bottom scroll limit */ @@ -181,6 +176,16 @@ typedef struct { const Arg arg; } Shortcut; +typedef struct { + xkb_keysym_t 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; + typedef struct { int axis; int dir; @@ -193,56 +198,38 @@ void redraw(void); int tattrset(int); void tnew(int, int); +void tresize(int, int); void tsetdirt(int, int); void tsetdirtattr(int); -int match(uint, uint); -void ttynew(void); +void ttynew(char *, char *, char **); size_t ttyread(void); -void ttyresize(void); +void ttyresize(int, int); void ttysend(char *, size_t); void ttywrite(const char *, size_t); void resettitle(void); -char *kmap(xkb_keysym_t, uint); -void cresize(int, int); void selclear(void); - void selinit(void); void selnormalize(void); int selected(int, int); char *getsel(void); -int x2col(int); -int y2row(int); -size_t utf8decode(char *, Rune *, size_t); +size_t utf8decode(const char *, Rune *, size_t); size_t utf8encode(Rune, char *); void *xmalloc(size_t); +void *xrealloc(void *, size_t); char *xstrdup(char *); -void usage(void); - /* Globals */ extern TermWindow win; extern Term term; extern Selection sel; extern int cmdfd; extern pid_t pid; -extern char **opt_cmd; -extern char *opt_class; -extern char *opt_embed; -extern char *opt_font; -extern char *opt_io; -extern char *opt_line; -extern char *opt_name; -extern char *opt_title; extern int oldbutton; -extern char *usedfont; -extern double usedfontsize; -extern double defaultfontsize; - /* config.h globals */ extern char font[]; extern int borderpx; @@ -254,6 +241,7 @@ extern int allowaltscreen; // extern unsigned int xfps; // extern unsigned int actionfps; extern unsigned int cursorthickness; +// extern int bellvolume; extern unsigned int blinktimeout; extern char termname[]; extern const char *colorname[]; @@ -273,7 +261,12 @@ extern MouseShortcut mshortcuts[]; extern size_t mshortcutslen; extern Shortcut shortcuts[]; extern size_t shortcutslen; +extern xkb_keysym_t mappedkeys[]; +extern size_t mappedkeyslen; +extern uint ignoremod; extern uint forceselmod; +extern Key key[]; +extern size_t keyslen; extern uint selmasks[]; extern size_t selmaskslen; extern char ascii_printable[]; diff --git a/win.h b/win.h index 228a4b1..092b448 100644 --- a/win.h +++ b/win.h @@ -12,22 +12,19 @@ void draw(void); void drawregion(int, int, int, int); -void run(void); // void xbell(int); // void xclipcopy(void); // void xclippaste(void); // void xhints(void); -void wlinit(void); void wlloadcols(void); int wlsetcolorname(int, const char*); -void wlloadfonts(char *, double); -// void xsetenv(void); void wlsettitle(char *); // void xsetpointermotion(int); -void wlseturgency(int); -void wlunloadfonts(void); -void wlresize(int, int); void wlselpaste(void); -// unsigned long xwinid(void); +void setsel(char*); +void zoom(const Arg *); +void zoomabs(const Arg *); +void zoomreset(const Arg *); + void wlneeddraw(void); diff --git a/wl.c b/wl.c index dbb27b2..3219a7c 100644 --- a/wl.c +++ b/wl.c @@ -22,9 +22,10 @@ #include #include +static char *argv0; #include "arg.h" -#include "win.h" #include "st.h" +#include "win.h" #include "xdg-shell-client-protocol.h" #define DRAW_BUF_SIZ 20*1024 @@ -57,6 +58,7 @@ typedef struct { int px, py; /* pointer x and y */ int vis; struct wl_callback * framecb; + uint32_t globalserial; /* global event serial */ bool needdraw; } Wayland; @@ -102,6 +104,18 @@ typedef struct { struct timespec last; } Repeat; + + +/* TODO: Categorize these */ +static int x2col(int); +static int y2row(int); +static int match(uint, uint); +static char *kmap(xkb_keysym_t, uint); +static void wlresize(int, int); +static void cresize(int, int); +static void wlloadfonts(char *, double); +static void wlunloadfonts(void); + static void getbuttoninfo(void); static void wlmousereport(int, bool, int, int); static void wlmousereportbutton(uint32_t, uint32_t); @@ -172,6 +186,9 @@ static void datasrcsend(void *, struct wl_data_source *, const char *, int32_t); static void datasrccancelled(void *, struct wl_data_source *); +static void run(void); +static void usage(void); + /* Globals */ static DC dc; static Wayland wl; @@ -198,6 +215,11 @@ static struct wl_data_source_listener datasrclistener = { datasrctarget, datasrcsend, datasrccancelled }; static struct wl_data_offer_listener dataofferlistener = { dataofferoffer }; +enum window_state { + WIN_VISIBLE = 1, + WIN_FOCUSED = 2 +}; + /* Font Ring Cache */ enum { FRC_NORMAL, @@ -215,6 +237,137 @@ typedef struct { /* 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; + +int +x2col(int x) +{ + x -= borderpx; + x /= win.cw; + + return LIMIT(x, 0, term.col-1); +} + +int +y2row(int y) +{ + y -= borderpx; + y /= win.ch; + + return LIMIT(y, 0, term.row-1); +} + +int +match(uint mask, uint state) +{ + return mask == MOD_MASK_ANY || mask == (state & ~ignoremod); +} + +char* +kmap(xkb_keysym_t k, uint state) +{ + Key *kp; + int i; + + /* Check for mapped keys out of X11 function keys. */ + for (i = 0; i < mappedkeyslen; i++) { + if (mappedkeys[i] == k) + break; + } + if (i == mappedkeyslen) { + if ((k & 0xFFFF) < 0xFD00) + return NULL; + } + + for (kp = key; kp < key + keyslen; 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 +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); + wlresize(col, row); +} + +void +zoom(const Arg *arg) +{ + Arg larg; + + larg.f = usedfontsize + arg->f; + zoomabs(&larg); +} + +void +zoomabs(const Arg *arg) +{ + wlunloadfonts(); + wlloadfonts(usedfont, arg->f); + cresize(0, 0); + ttyresize(win.tw, win.th); + redraw(); + /* XXX: Should the window size be updated here because wayland doesn't + * * have a notion of hints? + * * xhints(); */ +} + +void +zoomreset(const Arg *arg) +{ + Arg larg; + if (defaultfontsize > 0) { + larg.f = defaultfontsize; + zoomabs(&larg); + } +} + +void +setsel(char * buf) +{ + wlsetsel(buf, wl.globalserial); +} void getbuttoninfo(void) @@ -383,6 +536,7 @@ ptrbutton(void * data, struct wl_pointer * pointer, uint32_t serial, if (button == BTN_MIDDLE) { wlselpaste(); } else if (button == BTN_LEFT) { + wl.globalserial = serial; if (sel.mode == SEL_READY) { getbuttoninfo(); selcopy(serial); @@ -606,6 +760,7 @@ kbdkey(void *data, struct wl_keyboard *keyboard, uint32_t serial, uint32_t time, return; } + wl.globalserial = serial; ksym = xkb_state_key_get_one_sym(wl.xkb.state, key + 8); len = xkb_keysym_to_utf8(ksym, buf, sizeof buf); if (len > 0) @@ -690,6 +845,7 @@ kbdrepeatinfo(void *data, struct wl_keyboard *keyboard, int32_t rate, keyrepeatdelay = delay; keyrepeatinterval = 1000 / rate; } + void wlresize(int col, int row) { @@ -708,15 +864,10 @@ wlresize(int col, int row) void wlsettitle(char *title) { + DEFAULT(title, "st-wl"); xdg_toplevel_set_title(wl.xdgtoplevel, title); } -void -wlseturgency(int add) -{ - /* XXX: no urgency equivalent yet in wayland */ -} - void surfenter(void *data, struct wl_surface *surface, struct wl_output *output) { @@ -756,7 +907,7 @@ xdgtoplevelconfigure(void *data, struct xdg_toplevel *toplevel, return; cresize(w, h); if (wl.configured) - ttyresize(); + ttyresize(win.tw, win.th); else wl.configured = true; } @@ -1644,8 +1795,8 @@ run(void) wl_display_roundtrip(wl.dpy); if (!wl.configured) cresize(win.w, win.h); - ttynew(); - ttyresize(); + ttynew(opt_line, opt_io, opt_cmd); + ttyresize(win.tw, win.th); draw(); clock_gettime(CLOCK_MONOTONIC, &last); @@ -1722,6 +1873,19 @@ run(void) } } +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[]) { From e0cb46f2c998699b48b0c885a404d7e8d88d0bcd Mon Sep 17 00:00:00 2001 From: ian <42294085+ianbeyst@users.noreply.github.com> Date: Fri, 14 Jun 2019 16:28:57 +0200 Subject: [PATCH 123/129] pre-merge changes up until st upstream commit 52d6fb1 --- config.def.h | 68 ++++++------- st.c | 142 ++++++++++++--------------- st.h | 98 ++++--------------- win.h | 19 +--- wl.c | 270 +++++++++++++++++++++++++++++++-------------------- 5 files changed, 280 insertions(+), 317 deletions(-) diff --git a/config.def.h b/config.def.h index eb2133f..3000f9b 100644 --- a/config.def.h +++ b/config.def.h @@ -5,8 +5,8 @@ * * font: see http://freedesktop.org/software/fontconfig/fontconfig-user.html */ -char font[] = "Liberation Mono:pixelsize=12:antialias=true:autohint=true"; -int borderpx = 2; +static char font[] = "Liberation Mono:pixelsize=12:antialias=true:autohint=true"; +static int borderpx = 2; /* * What program is execed by st-wl depends of these precedence rules: @@ -16,45 +16,45 @@ 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"; +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 */ -float cwscale = 1.0; -float chscale = 1.0; +static float cwscale = 1.0; +static float chscale = 1.0; /* * word delimiter string * * More advanced example: " `'\"()[]{}" */ -static char worddelimiters[] = " "; +char *worddelimiters = " "; /* selection timeouts (in milliseconds) */ -unsigned int doubleclicktimeout = 300; -unsigned int tripleclicktimeout = 600; +static unsigned int doubleclicktimeout = 300; +static unsigned int tripleclicktimeout = 600; /* alt screens */ int allowaltscreen = 1; /* key repeat timeouts (in milliseconds) */ -unsigned int keyrepeatdelay = 500; -unsigned int keyrepeatinterval = 25; +static unsigned int keyrepeatdelay = 500; +static unsigned int keyrepeatinterval = 25; /* * blinking timeout (set to 0 to disable blinking) for the terminal blinking * attribute. */ -unsigned int blinktimeout = 800; +static unsigned int blinktimeout = 800; /* * thickness of underline and bar cursors */ -unsigned int cursorthickness = 2; +static unsigned int cursorthickness = 2; /* * bell volume. It must be a value between -100 and 100. Use 0 for disabling @@ -65,7 +65,7 @@ unsigned int cursorthickness = 2; */ /* default TERM value */ -char termname[] = "st-wl-256color"; +char *termname = "st-wl-256color"; /* * spaces per tab @@ -82,10 +82,10 @@ char termname[] = "st-wl-256color"; * * stty tabs */ -static unsigned int tabspaces = 8; +unsigned int tabspaces = 8; /* Terminal colors (16 first used in escape sequence) */ -const char *colorname[] = { +static const char *colorname[] = { /* 8 normal colors */ "black", "red3", @@ -120,8 +120,8 @@ const char *colorname[] = { */ unsigned int defaultfg = 7; unsigned int defaultbg = 0; -unsigned int defaultcs = 256; -unsigned int defaultrcs = 257; +static unsigned int defaultcs = 256; +static unsigned int defaultrcs = 257; /* * Default shape of cursor @@ -130,36 +130,36 @@ unsigned int defaultrcs = 257; * 6: Bar ("|") * 7: Snowman ("☃") */ -unsigned int cursorshape = 2; +static unsigned int cursorshape = 2; /* * Default columns and rows numbers */ -unsigned int cols = 80; -unsigned int rows = 24; +static unsigned int cols = 80; +static unsigned int rows = 24; /* * Default shape of the mouse cursor */ -char mouseshape[] = "xterm"; +static char mouseshape[] = "xterm"; /* * Color used to display font attributes when fontconfig selected a font which * doesn't match the ones requested. */ -unsigned int defaultattr = 11; +static unsigned int defaultattr = 11; /* * Internal mouse shortcuts. * Beware that overloading Button1 will disable the selection. */ -MouseShortcut mshortcuts[] = { +static MouseShortcut mshortcuts[] = { /* button mask string */ { -1, MOD_MASK_NONE, "" } }; -Axiskey ashortcuts[] = { +static Axiskey ashortcuts[] = { /* axis direction mask string */ { AXIS_VERTICAL, +1, MOD_MASK_ANY, "\031"}, { AXIS_VERTICAL, -1, MOD_MASK_ANY, "\005"}, @@ -169,7 +169,7 @@ Axiskey ashortcuts[] = { #define MODKEY MOD_MASK_ALT #define TERMMOD (MOD_MASK_CTRL|MOD_MASK_SHIFT) -Shortcut shortcuts[] = { +static Shortcut shortcuts[] = { /* modifier key function argument */ { MOD_MASK_ANY, XKB_KEY_Break, sendbreak, {.i = 0} }, { MOD_MASK_CTRL, XKB_KEY_Print, toggleprinter, {.i = 0} }, @@ -214,23 +214,23 @@ Shortcut shortcuts[] = { * If you want keys other than the X11 function keys (0xFD00 - 0xFFFF) * to be mapped below, add them to this array. */ -xkb_keysym_t mappedkeys[] = { -1 }; +static xkb_keysym_t mappedkeys[] = { -1 }; /* State bits to ignore when matching key or button events. */ -uint ignoremod = 0; +static uint ignoremod = 0; /* * Override mouse-select while mask is active (when MODE_MOUSE is set). * Note that if you want to use MOD_MASK_SHIFT with selmasks, set this to an * other modifier, set to 0 to not use it. */ -uint forceselmod = MOD_MASK_SHIFT; +static uint forceselmod = MOD_MASK_SHIFT; /* * This is the huge key array which defines all compatibility to the Linux * world. Please decide about changes wisely. */ -Key key[] = { +static Key key[] = { /* keysym mask string appkey appcursor crlf */ { XKB_KEY_KP_Home, MOD_MASK_SHIFT, "\033[2J", 0, -1, 0}, { XKB_KEY_KP_Home, MOD_MASK_SHIFT, "\033[1;2H", 0, +1, 0}, @@ -450,7 +450,7 @@ Key key[] = { * ButtonRelease and MotionNotify. * If no match is found, regular selection is used. */ -uint selmasks[] = { +static uint selmasks[] = { [SEL_RECTANGULAR] = MOD_MASK_ALT, }; @@ -458,7 +458,7 @@ uint selmasks[] = { * Printable characters in ASCII, used to estimate the advance width * of single wide characters. */ -char ascii_printable[] = +static char ascii_printable[] = " !\"#$%&'()*+,-./0123456789:;<=>?" "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_" "`abcdefghijklmnopqrstuvwxyz{|}~"; diff --git a/st.c b/st.c index 52cc9f9..922eda0 100644 --- a/st.c +++ b/st.c @@ -21,17 +21,7 @@ #include #include #include -#include #include -/* for BTN_* definitions */ -#include -#include -#include -#include - -/* Wayland */ -#include - #include "st.h" #include "win.h" @@ -114,19 +104,6 @@ typedef struct { int narg; /* nb of args */ } STREscape; -/* 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 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" static void execsh(char **); static void stty(char **); @@ -163,6 +140,7 @@ static void tscrollup(int, int); static void tscrolldown(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 tsetmode(int, int, int *, int); @@ -188,13 +166,12 @@ static char *base64dec(const char *); static ssize_t xwrite(int, const char *, size_t); /* Globals */ -TermWindow win; Term term; -Selection sel; int cmdfd; pid_t pid; int oldbutton = 3; /* button event on startup: 3 = release */ +static Selection sel; static CSIEscape csiescseq; static STREscape strescseq; static int iofd = 1; @@ -204,15 +181,6 @@ 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}; -/* config.h array lengths */ -size_t colornamelen = LEN(colorname); -size_t mshortcutslen = LEN(mshortcuts); -size_t shortcutslen = LEN(shortcuts); -size_t selmaskslen = LEN(selmasks); -size_t keyslen = LEN(key); -size_t mappedkeyslen = LEN(mappedkeys); -size_t ashortcutslen = LEN(ashortcuts); - ssize_t xwrite(int fd, const char *s, size_t len) { @@ -398,13 +366,9 @@ base64dec(const char *src) void selinit(void) { - sel.tclick1 = 0; - sel.tclick2 = 0; sel.mode = SEL_IDLE; sel.snap = 0; sel.ob.x = -1; - sel.primary = NULL; - sel.source = NULL; } int @@ -421,6 +385,52 @@ tlinelen(int y) return i; } +void +selstart(int col, int row, int snap) +{ + 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(); + + if (sel.snap != 0) + sel.mode = SEL_READY; + tsetdirt(sel.nb.y, sel.ne.y); +} + +void +selextend(int col, int row, int type, int done) +{ + int oldey, oldex, oldsby, oldsey, oldtype; + + if (!sel.mode) + return; + if (done && sel.mode == SEL_EMPTY) { + selclear(); + return; + } + + oldey = sel.oe.y; + oldex = sel.oe.x; + oldsby = sel.nb.y; + oldsey = sel.ne.y; + oldtype = sel.type; + + 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 selnormalize(void) { @@ -452,7 +462,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) @@ -591,24 +602,6 @@ getsel(void) return str; } -void -selpaste(const Arg *dummy) -{ - wlselpaste(); -} - -void -clipcopy(const Arg *dummy) -{ - // TODO: Check what xclipcopy() does -} - -void -clippaste(const Arg *dummy) -{ - // TODO: Check what xclippaste() does -} - void selclear(void) { @@ -721,7 +714,6 @@ void ttynew(char *line, char *out, char **args) { int m, s; - struct winsize w = {term.row, term.col, 0, 0}; if (out) { term.mode |= MODE_PRINT; @@ -742,7 +734,7 @@ ttynew(char *line, char *out, char **args) } /* 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()) { @@ -793,12 +785,15 @@ ttyread(void) } 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; + if (may_echo && IS_SET(MODE_ECHO)) + twrite(s, n, 1); + /* * 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 @@ -849,14 +844,6 @@ ttywrite(const char *s, size_t n) die("write error on tty: %s\n", strerror(errno)); } -void -ttysend(char *s, size_t n) -{ - ttywrite(s, n); - if (IS_SET(MODE_ECHO)) - twrite(s, n, 1); -} - void ttyresize(int tw, int th) { @@ -1581,7 +1568,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 Forward */ case 'a': /* HPR -- Cursor Forward */ @@ -1709,7 +1696,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 */ @@ -1731,11 +1718,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 (wlsetcursor(csiescseq.arg[0])) goto unknown; - } - win.cursor = csiescseq.arg[0]; break; default: goto unknown; @@ -1799,8 +1783,8 @@ strhandle(void) dec = base64dec(strescseq.args[2]); if (dec) { - setsel(dec); - clipcopy(NULL); + wlsetsel(dec); + wlclipcopy(); } else { fprintf(stderr, "erresc: invalid base64\n"); } @@ -1930,7 +1914,7 @@ iso14755(const Arg *arg) (*e != '\n' && *e != '\0')) return; - ttysend(uc, utf8encode(utf32, uc)); + ttywrite(uc, utf8encode(utf32, uc), 1); } void @@ -2144,7 +2128,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 */ @@ -2216,7 +2200,7 @@ 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(); diff --git a/st.h b/st.h index 782c33a..9466692 100644 --- a/st.h +++ b/st.h @@ -133,12 +133,6 @@ typedef struct { int cursor; /* cursor style */ } TermWindow; -typedef struct { - uint b; - uint mask; - char *s; -} MouseShortcut; - typedef struct { int mode; int type; @@ -154,12 +148,7 @@ typedef struct { int x, y; } nb, ne, ob, oe; - char *primary; //*clipboard, deprecated on wayland int alt; - uint32_t tclick1; - uint32_t tclick2; - - struct wl_data_source *source; } Selection; typedef union { @@ -169,48 +158,31 @@ typedef union { const void *v; } Arg; -typedef struct { - uint mod; - xkb_keysym_t keysym; - void (*func)(const Arg *); - const Arg arg; -} Shortcut; - -typedef struct { - xkb_keysym_t 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; - -typedef struct { - int axis; - int dir; - uint mask; - char s[ESC_BUF_SIZ]; -} Axiskey; - void die(const char *, ...); void redraw(void); +void iso14755(const Arg *); +void numlock(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 tsetdirt(int, int); void tsetdirtattr(int); void ttynew(char *, char *, char **); size_t ttyread(void); void ttyresize(int, int); -void ttysend(char *, size_t); -void ttywrite(const char *, size_t); +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); void selnormalize(void); int selected(int, int); char *getsel(void); @@ -223,55 +195,19 @@ void *xrealloc(void *, size_t); char *xstrdup(char *); /* Globals */ -extern TermWindow win; extern Term term; -extern Selection sel; extern int cmdfd; extern pid_t pid; extern int oldbutton; /* config.h globals */ -extern char font[]; -extern int borderpx; -extern float cwscale; -extern float chscale; -extern unsigned int doubleclicktimeout; -extern unsigned int tripleclicktimeout; +extern char *shell; +extern char *utmp; +extern char *stty_args; +extern char *vtiden; +extern char *worddelimiters; extern int allowaltscreen; -// extern unsigned int xfps; -// extern unsigned int actionfps; -extern unsigned int cursorthickness; -// extern int bellvolume; -extern unsigned int blinktimeout; -extern char termname[]; -extern const char *colorname[]; -extern size_t colornamelen; +extern char *termname; +extern unsigned int tabspaces; extern unsigned int defaultfg; extern unsigned int defaultbg; -extern unsigned int defaultcs; -extern unsigned int defaultrcs; -extern unsigned int cursorshape; -extern unsigned int cols; -extern unsigned int rows; -extern char mouseshape[]; -extern unsigned int mousefg; -extern unsigned int mousebg; -extern unsigned int defaultattr; -extern MouseShortcut mshortcuts[]; -extern size_t mshortcutslen; -extern Shortcut shortcuts[]; -extern size_t shortcutslen; -extern xkb_keysym_t mappedkeys[]; -extern size_t mappedkeyslen; -extern uint ignoremod; -extern uint forceselmod; -extern Key key[]; -extern size_t keyslen; -extern uint selmasks[]; -extern size_t selmaskslen; -extern char ascii_printable[]; - -extern unsigned int keyrepeatdelay; -extern unsigned int keyrepeatinterval; -extern Axiskey ashortcuts[]; -extern size_t ashortcutslen; diff --git a/win.h b/win.h index 092b448..7b9b961 100644 --- a/win.h +++ b/win.h @@ -1,30 +1,17 @@ /* See LICENSE for license details. */ -/* Key modifiers */ -#define MOD_MASK_ANY UINT_MAX -#define MOD_MASK_NONE 0 -#define MOD_MASK_CTRL (1<<0) -#define MOD_MASK_ALT (1<<1) -#define MOD_MASK_SHIFT (1<<2) -#define MOD_MASK_LOGO (1<<3) - -#define AXIS_VERTICAL WL_POINTER_AXIS_VERTICAL_SCROLL - void draw(void); void drawregion(int, int, int, int); // void xbell(int); -// void xclipcopy(void); -// void xclippaste(void); +void wlclipcopy(void); // void xhints(void); void wlloadcols(void); int wlsetcolorname(int, const char*); void wlsettitle(char *); +int wlsetcursor(int); // void xsetpointermotion(int); void wlselpaste(void); -void setsel(char*); -void zoom(const Arg *); -void zoomabs(const Arg *); -void zoomreset(const Arg *); +void wlsetsel(char*); void wlneeddraw(void); diff --git a/wl.c b/wl.c index 3219a7c..9019c6f 100644 --- a/wl.c +++ b/wl.c @@ -30,6 +30,58 @@ static char *argv0; #define DRAW_BUF_SIZ 20*1024 +/* types used in config.h */ +typedef struct { + uint mod; + xkb_keysym_t keysym; + void (*func)(const Arg *); + const Arg arg; +} Shortcut; + +typedef struct { + uint b; + uint mask; + char *s; +} MouseShortcut; + +typedef struct { + xkb_keysym_t 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; + +typedef struct { + int axis; + int dir; + uint mask; + char s[ESC_BUF_SIZ]; +} Axiskey; + +/* Key modifiers */ +#define MOD_MASK_ANY UINT_MAX +#define MOD_MASK_NONE 0 +#define MOD_MASK_CTRL (1<<0) +#define MOD_MASK_ALT (1<<1) +#define MOD_MASK_SHIFT (1<<2) +#define MOD_MASK_LOGO (1<<3) + +#define AXIS_VERTICAL WL_POINTER_AXIS_VERTICAL_SCROLL + +/* function definitions used in config.h */ +static void clipcopy(const Arg *); +static void clippaste(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" + typedef struct { struct xkb_context *ctx; struct xkb_keymap *keymap; @@ -62,6 +114,13 @@ typedef struct { bool needdraw; } Wayland; +typedef struct { + struct wl_data_source *source; + char *primary; + uint32_t tclick1; + uint32_t tclick2; +} WlSelection; + typedef struct { int height; int width; @@ -116,7 +175,7 @@ static void cresize(int, int); static void wlloadfonts(char *, double); static void wlunloadfonts(void); -static void getbuttoninfo(void); +static void mousesel(int); static void wlmousereport(int, bool, int, int); static void wlmousereportbutton(uint32_t, uint32_t); static void wlmousereportmotion(wl_fixed_t, wl_fixed_t); @@ -131,9 +190,8 @@ static void ptrbutton(void *, struct wl_pointer *, uint32_t, uint32_t, uint32_t, uint32_t); static void ptraxis(void *, struct wl_pointer *, uint32_t, uint32_t, wl_fixed_t); -static void wlsetsel(char*, uint32_t); +static void setsel(char*, uint32_t); static inline void selwritebuf(char *, int); -static void selcopy(uint32_t); /* Keyboard stuff */ static void kbdkeymap(void *, struct wl_keyboard *, uint32_t, int32_t, @@ -192,6 +250,8 @@ static void usage(void); /* Globals */ static DC dc; static Wayland wl; +static WlSelection wlsel; +static TermWindow win; static WLD wld; static Cursor cursor; static Repeat repeat; @@ -250,6 +310,16 @@ static char *opt_line = NULL; static char *opt_name = NULL; static char *opt_title = NULL; +int +wlsetcursor(int cursor) +{ + DEFAULT(cursor, 1); + if (!BETWEEN(cursor, 0, 6)) + return 1; + win.cursor = cursor; + return 0; +} + int x2col(int x) { @@ -281,16 +351,16 @@ kmap(xkb_keysym_t k, uint state) int i; /* Check for mapped keys out of X11 function keys. */ - for (i = 0; i < mappedkeyslen; i++) { + for (i = 0; i < LEN(mappedkeys); i++) { if (mappedkeys[i] == k) break; } - if (i == mappedkeyslen) { + if (i == LEN(mappedkeys)) { if ((k & 0xFFFF) < 0xFD00) return NULL; } - for (kp = key; kp < key + keyslen; kp++) { + for (kp = key; kp < key + LEN(key); kp++) { if (kp->k != k) continue; @@ -329,6 +399,7 @@ cresize(int width, int height) tresize(col, row); wlresize(col, row); + ttyresize(win.tw, win.th); } void @@ -346,7 +417,6 @@ zoomabs(const Arg *arg) wlunloadfonts(); wlloadfonts(usedfont, arg->f); cresize(0, 0); - ttyresize(win.tw, win.th); redraw(); /* XXX: Should the window size be updated here because wayland doesn't * * have a notion of hints? @@ -364,30 +434,51 @@ zoomreset(const Arg *arg) } void -setsel(char * buf) +wlclipcopy(void) { - wlsetsel(buf, wl.globalserial); + clipcopy(NULL); } void -getbuttoninfo(void) +clipcopy(const Arg * dummy) { - int type; - uint state = wl.xkb.mods & ~forceselmod; + // TODO: Implement this! +} + +void +clippaste(const Arg * dummy) +{ + // TODO: Implement this! +} + +void +selpaste(const Arg * dummy) +{ + // TODO: Implement this! +} - sel.alt = IS_SET(MODE_ALTSCREEN); +void +wlsetsel(char * buf) +{ + setsel(buf, wl.globalserial); +} - sel.oe.x = x2col(wl.px); - sel.oe.y = y2row(wl.py); - selnormalize(); +void +mousesel(int done) +{ + int type, seltype = SEL_REGULAR; + uint state = wl.xkb.mods & ~forceselmod; - sel.type = SEL_REGULAR; - for (type = 1; type < selmaskslen; ++type) { + for (type = 1; type < LEN(selmasks); ++type) { if (match(selmasks[type], state)) { - sel.type = type; + seltype = type; break; } } + + selextend(x2col(wl.px), y2row(wl.py), seltype, done); + if (done) + setsel(getsel(), wl.globalserial); } void @@ -412,7 +503,7 @@ wlmousereport(int button, bool release, int x, int y) return; } - ttywrite(buf, len); + ttywrite(buf, len, 0); } void @@ -496,8 +587,6 @@ void ptrmotion(void *data, struct wl_pointer * pointer, uint32_t serial, wl_fixed_t x, wl_fixed_t y) { - int oldey, oldex, oldsby, oldsey; - if (IS_SET(MODE_MOUSE)) { wlmousereportmotion(x, y); return; @@ -506,18 +595,7 @@ ptrmotion(void *data, struct wl_pointer * pointer, uint32_t serial, wl.px = wl_fixed_to_int(x); wl.py = wl_fixed_to_int(y); - 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(); - - if (oldey != sel.oe.y || oldex != sel.oe.x) - tsetdirt(MIN(sel.nb.y, oldsby), MAX(sel.ne.y, oldsey)); + mousesel(0); } void @@ -525,6 +603,7 @@ ptrbutton(void * data, struct wl_pointer * pointer, uint32_t serial, uint32_t time, uint32_t button, uint32_t state) { MouseShortcut *ms; + int snap; if (IS_SET(MODE_MOUSE) && !(wl.xkb.mods & forceselmod)) { wlmousereportbutton(button, state); @@ -535,52 +614,36 @@ ptrbutton(void * data, struct wl_pointer * pointer, uint32_t serial, case WL_POINTER_BUTTON_STATE_RELEASED: if (button == BTN_MIDDLE) { wlselpaste(); - } else if (button == BTN_LEFT) { + } else if (button == BTN_LEFT) { wl.globalserial = serial; - if (sel.mode == SEL_READY) { - getbuttoninfo(); - selcopy(serial); - } else - selclear(); - sel.mode = SEL_IDLE; - tsetdirt(sel.nb.y, sel.ne.y); - } + mousesel(1); + } break; case WL_POINTER_BUTTON_STATE_PRESSED: - for (ms = mshortcuts; ms < mshortcuts + mshortcutslen; ms++) { + for (ms = mshortcuts; ms < mshortcuts + LEN(mshortcuts); ms++) { if (button == ms->b && match(ms->mask, wl.xkb.mods)) { - ttysend(ms->s, strlen(ms->s)); + ttywrite(ms->s, strlen(ms->s), 1); return; } } if (button == BTN_LEFT) { - /* Clear previous selection, logically and visually. */ - selclear(); - sel.mode = SEL_EMPTY; - sel.type = SEL_REGULAR; - sel.oe.x = sel.ob.x = x2col(wl.px); - sel.oe.y = sel.ob.y = y2row(wl.py); - /* * If the user clicks below predefined timeouts * specific snapping behaviour is exposed. */ - if (time - sel.tclick2 <= tripleclicktimeout) { - sel.snap = SNAP_LINE; - } else if (time - sel.tclick1 <= doubleclicktimeout) { - sel.snap = SNAP_WORD; + if (time - wlsel.tclick2 <= tripleclicktimeout) { + snap = SNAP_LINE; + } else if (time - wlsel.tclick1 <= doubleclicktimeout) { + snap = SNAP_WORD; } else { - sel.snap = 0; + snap = 0; } - selnormalize(); + wlsel.tclick2 = wlsel.tclick1; + wlsel.tclick1 = time; - if (sel.snap != 0) - sel.mode = SEL_READY; - tsetdirt(sel.nb.y, sel.ne.y); - sel.tclick2 = sel.tclick1; - sel.tclick1 = time; + selstart(x2col(wl.px), y2row(wl.py), snap); } break; } @@ -598,29 +661,29 @@ ptraxis(void * data, struct wl_pointer * pointer, uint32_t time, uint32_t axis, return; } - for (ak = ashortcuts; ak < ashortcuts + ashortcutslen; ak++) { + for (ak = ashortcuts; ak < ashortcuts + LEN(ashortcuts); ak++) { if (axis == ak->axis && dir == ak->dir && match(ak->mask, wl.xkb.mods)) { - ttysend(ak->s, strlen(ak->s)); + ttywrite(ak->s, strlen(ak->s), 1); return; } } } void -wlsetsel(char *str, uint32_t serial) +setsel(char *str, uint32_t serial) { - free(sel.primary); - sel.primary = str; + free(wlsel.primary); + wlsel.primary = str; if (str) { - sel.source = wl_data_device_manager_create_data_source(wl.datadevmanager); - wl_data_source_add_listener(sel.source, &datasrclistener, NULL); - wl_data_source_offer(sel.source, "text/plain; charset=utf-8"); + wlsel.source = wl_data_device_manager_create_data_source(wl.datadevmanager); + wl_data_source_add_listener(wlsel.source, &datasrclistener, NULL); + wl_data_source_offer(wlsel.source, "text/plain; charset=utf-8"); } else { - sel.source = NULL; + wlsel.source = NULL; } - wl_data_device_set_selection(wl.datadev, sel.source, serial); + wl_data_device_set_selection(wl.datadev, wlsel.source, serial); } void @@ -639,7 +702,7 @@ selwritebuf(char *buf, int len) *repl++ = '\r'; } - ttysend(buf, len); + ttywrite(buf, len, 1); } void @@ -650,11 +713,11 @@ wlselpaste(void) if (wl.seloffer) { if (IS_SET(MODE_BRCKTPASTE)) - ttywrite("\033[200~", 6); + ttywrite("\033[200~", 6, 0); /* check if we are pasting from ourselves */ - if (sel.source) { - str = sel.primary; - left = strlen(sel.primary); + if (wlsel.source) { + str = wlsel.primary; + left = strlen(wlsel.primary); while (left > 0) { len = MIN(sizeof buf, left); memcpy(buf, str, len); @@ -673,16 +736,10 @@ wlselpaste(void) close(fds[0]); } if (IS_SET(MODE_BRCKTPASTE)) - ttywrite("\033[201~", 6); + ttywrite("\033[201~", 6, 0); } } -void -selcopy(uint32_t serial) -{ - wlsetsel(getsel(), serial); -} - void kbdkeymap(void *data, struct wl_keyboard *keyboard, uint32_t format, int32_t fd, uint32_t size) @@ -721,7 +778,7 @@ kbdenter(void *data, struct wl_keyboard *keyboard, uint32_t serial, { win.state |= WIN_FOCUSED; if (IS_SET(MODE_FOCUS)) - ttywrite("\033[I", 3); + ttywrite("\033[I", 3, 0); /* need to redraw the cursor */ wlneeddraw(); } @@ -734,7 +791,7 @@ kbdleave(void *data, struct wl_keyboard *keyboard, uint32_t serial, wl.seloffer = NULL; win.state &= ~WIN_FOCUSED; if (IS_SET(MODE_FOCUS)) - ttywrite("\033[O", 3); + ttywrite("\033[O", 3, 0); /* need to redraw the cursor */ wlneeddraw(); /* disable key repeat */ @@ -767,7 +824,7 @@ kbdkey(void *data, struct wl_keyboard *keyboard, uint32_t serial, uint32_t time, --len; /* 1. shortcuts */ - for (bp = shortcuts; bp < shortcuts + shortcutslen; bp++) { + for (bp = shortcuts; bp < shortcuts + LEN(shortcuts); bp++) { if (ksym == bp->keysym && match(bp->mod, wl.xkb.mods)) { bp->func(&(bp->arg)); return; @@ -814,7 +871,7 @@ kbdkey(void *data, struct wl_keyboard *keyboard, uint32_t serial, uint32_t time, repeat.len = len; repeat.started = false; clock_gettime(CLOCK_MONOTONIC, &repeat.last); - ttysend(str, len); + ttywrite(str, len, 1); } void @@ -906,9 +963,7 @@ xdgtoplevelconfigure(void *data, struct xdg_toplevel *toplevel, if (w == win.w && h == win.h) return; cresize(w, h); - if (wl.configured) - ttyresize(win.tw, win.th); - else + if (!wl.configured) wl.configured = true; } @@ -957,7 +1012,7 @@ wlloadcols(void) { int i; - dc.collen = MAX(colornamelen, 256); + dc.collen = MAX(LEN(colorname), 256); dc.col = xmalloc(dc.collen * sizeof(uint32_t)); for (i = 0; i < dc.collen; i++) @@ -1197,7 +1252,6 @@ drawregion(int x1, int y1, int x2, int y2) int ic, ib, x, y, ox; Glyph base, new; char buf[DRAW_BUF_SIZ]; - int ena_sel = sel.ob.x != -1 && sel.alt == IS_SET(MODE_ALTSCREEN); for (y = y1; y < y2; y++) { if (!term.dirty[y]) @@ -1210,7 +1264,7 @@ drawregion(int x1, int y1, int x2, int y2) new = term.line[y][x]; if (new.mode == ATTR_WDUMMY) continue; - if (ena_sel && selected(x, y)) + if (selected(x, y)) new.mode ^= ATTR_REVERSE; if (ib > 0 && (ATTRCMP(base, new) || ib >= DRAW_BUF_SIZ-UTF_SIZ)) { @@ -1514,7 +1568,6 @@ wldrawcursor(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); uint32_t drawcol; LIMIT(oldx, 0, term.col-1); @@ -1530,7 +1583,7 @@ wldrawcursor(void) /* remove the old cursor */ og = term.line[oldy][oldx]; - if (ena_sel && selected(oldx, oldy)) + if (selected(oldx, oldy)) og.mode ^= ATTR_REVERSE; wldrawglyph(og, oldx, oldy); if (oldx != curx || oldy != term.c.y) { @@ -1546,7 +1599,7 @@ wldrawcursor(void) if (IS_SET(MODE_REVERSE)) { g.mode |= ATTR_REVERSE; g.bg = defaultfg; - if (ena_sel && selected(term.c.x, term.c.y)) { + if (selected(term.c.x, term.c.y)) { drawcol = dc.col[defaultcs]; g.fg = defaultrcs; } else { @@ -1554,7 +1607,7 @@ wldrawcursor(void) g.fg = defaultcs; } } else { - if (ena_sel && selected(term.c.x, term.c.y)) { + if (selected(term.c.x, term.c.y)) { drawcol = dc.col[defaultrcs]; g.fg = defaultfg; g.bg = defaultrcs; @@ -1700,8 +1753,8 @@ void datasrcsend(void *data, struct wl_data_source *source, const char *mimetype, int32_t fd) { - char *buf = sel.primary; - int len = strlen(sel.primary); + char *buf = wlsel.primary; + int len = strlen(wlsel.primary); ssize_t ret; while ((ret = write(fd, buf, MIN(len, BUFSIZ))) > 0) { len -= ret; @@ -1713,8 +1766,8 @@ datasrcsend(void *data, struct wl_data_source *source, const char *mimetype, void datasrccancelled(void *data, struct wl_data_source *source) { - if (sel.source == source) { - sel.source = NULL; + if (wlsel.source == source) { + wlsel.source = NULL; selclear(); } wl_data_source_destroy(source); @@ -1781,6 +1834,11 @@ wlinit(void) wl.xkb.ctx = xkb_context_new(0); resettitle(); + + wlsel.tclick1 = 0; + wlsel.tclick2 = 0; + wlsel.primary = NULL; + wlsel.source = NULL; } void @@ -1793,10 +1851,8 @@ run(void) /* Look for initial configure. */ wl_display_roundtrip(wl.dpy); - if (!wl.configured) - cresize(win.w, win.h); ttynew(opt_line, opt_io, opt_cmd); - ttyresize(win.tw, win.th); + cresize(win.w, win.h); draw(); clock_gettime(CLOCK_MONOTONIC, &last); @@ -1846,7 +1902,7 @@ run(void) keyrepeatdelay)) { repeat.started = true; repeat.last = now; - ttysend(repeat.str, repeat.len); + ttywrite(repeat.str, repeat.len, 1); } else { msecs = MIN(msecs, (repeat.started ? \ keyrepeatinterval : keyrepeatdelay) - \ From 9b95f422812ff84ee29024dba0aea144902f5310 Mon Sep 17 00:00:00 2001 From: ian <42294085+ianbeyst@users.noreply.github.com> Date: Fri, 14 Jun 2019 18:26:46 +0200 Subject: [PATCH 124/129] pre-merge changes up until st upstream commit 88d8293 --- config.def.h | 418 +++++++++++++++++++++++++-------------------------- st.c | 145 ++++++++++++------ st.h | 34 +---- win.h | 42 ++++-- wl.c | 159 +++++++++++--------- 5 files changed, 428 insertions(+), 370 deletions(-) diff --git a/config.def.h b/config.def.h index 567a3e7..8de99af 100644 --- a/config.def.h +++ b/config.def.h @@ -231,216 +231,214 @@ static uint forceselmod = MOD_MASK_SHIFT; * world. Please decide about changes wisely. */ static Key key[] = { - /* keysym mask string appkey appcursor crlf */ - { XKB_KEY_KP_Home, MOD_MASK_SHIFT, "\033[2J", 0, -1, 0}, - { XKB_KEY_KP_Home, MOD_MASK_SHIFT, "\033[1;2H", 0, +1, 0}, - { XKB_KEY_KP_Home, MOD_MASK_ANY, "\033[H", 0, -1, 0}, - { XKB_KEY_KP_Home, MOD_MASK_ANY, "\033[1~", 0, +1, 0}, - { XKB_KEY_KP_Up, MOD_MASK_ANY, "\033Ox", +1, 0, 0}, - { XKB_KEY_KP_Up, MOD_MASK_ANY, "\033[A", 0, -1, 0}, - { XKB_KEY_KP_Up, MOD_MASK_ANY, "\033OA", 0, +1, 0}, - { XKB_KEY_KP_Down, MOD_MASK_ANY, "\033Or", +1, 0, 0}, - { XKB_KEY_KP_Down, MOD_MASK_ANY, "\033[B", 0, -1, 0}, - { XKB_KEY_KP_Down, MOD_MASK_ANY, "\033OB", 0, +1, 0}, - { XKB_KEY_KP_Left, MOD_MASK_ANY, "\033Ot", +1, 0, 0}, - { XKB_KEY_KP_Left, MOD_MASK_ANY, "\033[D", 0, -1, 0}, - { XKB_KEY_KP_Left, MOD_MASK_ANY, "\033OD", 0, +1, 0}, - { XKB_KEY_KP_Right, MOD_MASK_ANY, "\033Ov", +1, 0, 0}, - { XKB_KEY_KP_Right, MOD_MASK_ANY, "\033[C", 0, -1, 0}, - { XKB_KEY_KP_Right, MOD_MASK_ANY, "\033OC", 0, +1, 0}, - { XKB_KEY_KP_Prior, MOD_MASK_SHIFT, "\033[5;2~", 0, 0, 0}, - { XKB_KEY_KP_Prior, MOD_MASK_ANY, "\033[5~", 0, 0, 0}, - { XKB_KEY_KP_Begin, MOD_MASK_ANY, "\033[E", 0, 0, 0}, - { XKB_KEY_KP_End, MOD_MASK_CTRL, "\033[J", -1, 0, 0}, - { XKB_KEY_KP_End, MOD_MASK_CTRL, "\033[1;5F", +1, 0, 0}, - { XKB_KEY_KP_End, MOD_MASK_SHIFT, "\033[K", -1, 0, 0}, - { XKB_KEY_KP_End, MOD_MASK_SHIFT, "\033[1;2F", +1, 0, 0}, - { XKB_KEY_KP_End, MOD_MASK_ANY, "\033[4~", 0, 0, 0}, - { XKB_KEY_KP_Next, MOD_MASK_SHIFT, "\033[6;2~", 0, 0, 0}, - { XKB_KEY_KP_Next, MOD_MASK_ANY, "\033[6~", 0, 0, 0}, - { XKB_KEY_KP_Insert, MOD_MASK_SHIFT, "\033[2;2~", +1, 0, 0}, - { XKB_KEY_KP_Insert, MOD_MASK_SHIFT, "\033[4l", -1, 0, 0}, - { XKB_KEY_KP_Insert, MOD_MASK_CTRL, "\033[L", -1, 0, 0}, - { XKB_KEY_KP_Insert, MOD_MASK_CTRL, "\033[2;5~", +1, 0, 0}, - { XKB_KEY_KP_Insert, MOD_MASK_ANY, "\033[4h", -1, 0, 0}, - { XKB_KEY_KP_Insert, MOD_MASK_ANY, "\033[2~", +1, 0, 0}, - { XKB_KEY_KP_Delete, MOD_MASK_CTRL, "\033[M", -1, 0, 0}, - { XKB_KEY_KP_Delete, MOD_MASK_CTRL, "\033[3;5~", +1, 0, 0}, - { XKB_KEY_KP_Delete, MOD_MASK_SHIFT, "\033[2K", -1, 0, 0}, - { XKB_KEY_KP_Delete, MOD_MASK_SHIFT, "\033[3;2~", +1, 0, 0}, - { XKB_KEY_KP_Delete, MOD_MASK_ANY, "\033[P", -1, 0, 0}, - { XKB_KEY_KP_Delete, MOD_MASK_ANY, "\033[3~", +1, 0, 0}, - { XKB_KEY_KP_Multiply, MOD_MASK_ANY, "\033Oj", +2, 0, 0}, - { XKB_KEY_KP_Add, MOD_MASK_ANY, "\033Ok", +2, 0, 0}, - { XKB_KEY_KP_Enter, MOD_MASK_ANY, "\033OM", +2, 0, 0}, - { XKB_KEY_KP_Enter, MOD_MASK_ANY, "\r", -1, 0, -1}, - { XKB_KEY_KP_Enter, MOD_MASK_ANY, "\r\n", -1, 0, +1}, - { XKB_KEY_KP_Subtract, MOD_MASK_ANY, "\033Om", +2, 0, 0}, - { XKB_KEY_KP_Decimal, MOD_MASK_ANY, "\033On", +2, 0, 0}, - { XKB_KEY_KP_Divide, MOD_MASK_ANY, "\033Oo", +2, 0, 0}, - { XKB_KEY_KP_0, MOD_MASK_ANY, "\033Op", +2, 0, 0}, - { XKB_KEY_KP_1, MOD_MASK_ANY, "\033Oq", +2, 0, 0}, - { XKB_KEY_KP_2, MOD_MASK_ANY, "\033Or", +2, 0, 0}, - { XKB_KEY_KP_3, MOD_MASK_ANY, "\033Os", +2, 0, 0}, - { XKB_KEY_KP_4, MOD_MASK_ANY, "\033Ot", +2, 0, 0}, - { XKB_KEY_KP_5, MOD_MASK_ANY, "\033Ou", +2, 0, 0}, - { XKB_KEY_KP_6, MOD_MASK_ANY, "\033Ov", +2, 0, 0}, - { XKB_KEY_KP_7, MOD_MASK_ANY, "\033Ow", +2, 0, 0}, - { XKB_KEY_KP_8, MOD_MASK_ANY, "\033Ox", +2, 0, 0}, - { XKB_KEY_KP_9, MOD_MASK_ANY, "\033Oy", +2, 0, 0}, - { XKB_KEY_Up, MOD_MASK_SHIFT, "\033[1;2A", 0, 0, 0}, - { XKB_KEY_Up, MOD_MASK_ALT, "\033[1;3A", 0, 0, 0}, - { XKB_KEY_Up, MOD_MASK_SHIFT|MOD_MASK_ALT,"\033[1;4A", 0, 0, 0}, - { XKB_KEY_Up, MOD_MASK_CTRL, "\033[1;5A", 0, 0, 0}, - { XKB_KEY_Up,MOD_MASK_SHIFT|MOD_MASK_CTRL,"\033[1;6A", 0, 0, 0}, - { XKB_KEY_Up, MOD_MASK_CTRL|MOD_MASK_ALT,"\033[1;7A", 0, 0, 0}, - { XKB_KEY_Up,MOD_MASK_SHIFT|MOD_MASK_CTRL|MOD_MASK_ALT,"\033[1;8A",0,0,0}, - { XKB_KEY_Up, MOD_MASK_ANY, "\033[A", 0, -1, 0}, - { XKB_KEY_Up, MOD_MASK_ANY, "\033OA", 0, +1, 0}, - { XKB_KEY_Down, MOD_MASK_SHIFT, "\033[1;2B", 0, 0, 0}, - { XKB_KEY_Down, MOD_MASK_ALT, "\033[1;3B", 0, 0, 0}, - { XKB_KEY_Down,MOD_MASK_SHIFT|MOD_MASK_ALT,"\033[1;4B", 0, 0, 0}, - { XKB_KEY_Down, MOD_MASK_CTRL, "\033[1;5B", 0, 0, 0}, - { XKB_KEY_Down,MOD_MASK_SHIFT|MOD_MASK_CTRL,"\033[1;6B", 0, 0, 0}, - { XKB_KEY_Down,MOD_MASK_CTRL|MOD_MASK_ALT,"\033[1;7B", 0, 0, 0}, - { XKB_KEY_Down,MOD_MASK_SHIFT|MOD_MASK_CTRL|MOD_MASK_ALT,"\033[1;8B",0,0,0}, - { XKB_KEY_Down, MOD_MASK_ANY, "\033[B", 0, -1, 0}, - { XKB_KEY_Down, MOD_MASK_ANY, "\033OB", 0, +1, 0}, - { XKB_KEY_Left, MOD_MASK_SHIFT, "\033[1;2D", 0, 0, 0}, - { XKB_KEY_Left, MOD_MASK_ALT, "\033[1;3D", 0, 0, 0}, - { XKB_KEY_Left,MOD_MASK_SHIFT|MOD_MASK_ALT,"\033[1;4D", 0, 0, 0}, - { XKB_KEY_Left, MOD_MASK_CTRL, "\033[1;5D", 0, 0, 0}, - { XKB_KEY_Left,MOD_MASK_SHIFT|MOD_MASK_CTRL,"\033[1;6D", 0, 0, 0}, - { XKB_KEY_Left,MOD_MASK_CTRL|MOD_MASK_ALT,"\033[1;7D", 0, 0, 0}, - { XKB_KEY_Left,MOD_MASK_SHIFT|MOD_MASK_CTRL|MOD_MASK_ALT,"\033[1;8D",0,0,0}, - { XKB_KEY_Left, MOD_MASK_ANY, "\033[D", 0, -1, 0}, - { XKB_KEY_Left, MOD_MASK_ANY, "\033OD", 0, +1, 0}, - { XKB_KEY_Right, MOD_MASK_SHIFT, "\033[1;2C", 0, 0, 0}, - { XKB_KEY_Right, MOD_MASK_ALT, "\033[1;3C", 0, 0, 0}, - { XKB_KEY_Right,MOD_MASK_SHIFT|MOD_MASK_ALT,"\033[1;4C", 0, 0, 0}, - { XKB_KEY_Right, MOD_MASK_CTRL, "\033[1;5C", 0, 0, 0}, - { XKB_KEY_Right,MOD_MASK_SHIFT|MOD_MASK_CTRL,"\033[1;6C", 0, 0, 0}, - { XKB_KEY_Right,MOD_MASK_CTRL|MOD_MASK_ALT,"\033[1;7C", 0, 0, 0}, - { XKB_KEY_Right,MOD_MASK_SHIFT|MOD_MASK_CTRL|MOD_MASK_ALT,"\033[1;8C",0,0,0}, - { XKB_KEY_Right, MOD_MASK_ANY, "\033[C", 0, -1, 0}, - { XKB_KEY_Right, MOD_MASK_ANY, "\033OC", 0, +1, 0}, - { XKB_KEY_ISO_Left_Tab, MOD_MASK_SHIFT, "\033[Z", 0, 0, 0}, - { XKB_KEY_Return, MOD_MASK_ALT, "\033\r", 0, 0, -1}, - { XKB_KEY_Return, MOD_MASK_ALT, "\033\r\n", 0, 0, +1}, - { XKB_KEY_Return, MOD_MASK_ANY, "\r", 0, 0, -1}, - { XKB_KEY_Return, MOD_MASK_ANY, "\r\n", 0, 0, +1}, - { XKB_KEY_Insert, MOD_MASK_SHIFT, "\033[4l", -1, 0, 0}, - { XKB_KEY_Insert, MOD_MASK_SHIFT, "\033[2;2~", +1, 0, 0}, - { XKB_KEY_Insert, MOD_MASK_CTRL, "\033[L", -1, 0, 0}, - { XKB_KEY_Insert, MOD_MASK_CTRL, "\033[2;5~", +1, 0, 0}, - { XKB_KEY_Insert, MOD_MASK_ANY, "\033[4h", -1, 0, 0}, - { XKB_KEY_Insert, MOD_MASK_ANY, "\033[2~", +1, 0, 0}, - { XKB_KEY_Delete, MOD_MASK_CTRL, "\033[M", -1, 0, 0}, - { XKB_KEY_Delete, MOD_MASK_CTRL, "\033[3;5~", +1, 0, 0}, - { XKB_KEY_Delete, MOD_MASK_SHIFT, "\033[2K", -1, 0, 0}, - { XKB_KEY_Delete, MOD_MASK_SHIFT, "\033[3;2~", +1, 0, 0}, - { XKB_KEY_Delete, MOD_MASK_ANY, "\033[P", -1, 0, 0}, - { XKB_KEY_Delete, MOD_MASK_ANY, "\033[3~", +1, 0, 0}, - { XKB_KEY_BackSpace, MOD_MASK_NONE, "\177", 0, 0, 0}, - { XKB_KEY_BackSpace, MOD_MASK_CTRL, "\033\177", 0, 0, 0}, - { XKB_KEY_Home, MOD_MASK_SHIFT, "\033[2J", 0, -1, 0}, - { XKB_KEY_Home, MOD_MASK_SHIFT, "\033[1;2H", 0, +1, 0}, - { XKB_KEY_Home, MOD_MASK_ANY, "\033[H", 0, -1, 0}, - { XKB_KEY_Home, MOD_MASK_ANY, "\033[1~", 0, +1, 0}, - { XKB_KEY_End, MOD_MASK_CTRL, "\033[J", -1, 0, 0}, - { XKB_KEY_End, MOD_MASK_CTRL, "\033[1;5F", +1, 0, 0}, - { XKB_KEY_End, MOD_MASK_SHIFT, "\033[K", -1, 0, 0}, - { XKB_KEY_End, MOD_MASK_SHIFT, "\033[1;2F", +1, 0, 0}, - { XKB_KEY_End, MOD_MASK_ANY, "\033[4~", 0, 0, 0}, - { XKB_KEY_Prior, MOD_MASK_CTRL, "\033[5;5~", 0, 0, 0}, - { XKB_KEY_Prior, MOD_MASK_SHIFT, "\033[5;2~", 0, 0, 0}, - { XKB_KEY_Prior, MOD_MASK_ANY, "\033[5~", 0, 0, 0}, - { XKB_KEY_Next, MOD_MASK_CTRL, "\033[6;5~", 0, 0, 0}, - { XKB_KEY_Next, MOD_MASK_SHIFT, "\033[6;2~", 0, 0, 0}, - { XKB_KEY_Next, MOD_MASK_ANY, "\033[6~", 0, 0, 0}, - { XKB_KEY_F1, MOD_MASK_NONE, "\033OP" , 0, 0, 0}, - { XKB_KEY_F1, /* F13 */ MOD_MASK_SHIFT, "\033[1;2P", 0, 0, 0}, - { XKB_KEY_F1, /* F25 */ MOD_MASK_CTRL, "\033[1;5P", 0, 0, 0}, - { XKB_KEY_F1, /* F37 */ MOD_MASK_LOGO, "\033[1;6P", 0, 0, 0}, - { XKB_KEY_F1, /* F49 */ MOD_MASK_ALT, "\033[1;3P", 0, 0, 0}, - { XKB_KEY_F2, MOD_MASK_NONE, "\033OQ" , 0, 0, 0}, - { XKB_KEY_F2, /* F14 */ MOD_MASK_SHIFT, "\033[1;2Q", 0, 0, 0}, - { XKB_KEY_F2, /* F26 */ MOD_MASK_CTRL, "\033[1;5Q", 0, 0, 0}, - { XKB_KEY_F2, /* F38 */ MOD_MASK_LOGO, "\033[1;6Q", 0, 0, 0}, - { XKB_KEY_F2, /* F50 */ MOD_MASK_ALT, "\033[1;3Q", 0, 0, 0}, - { XKB_KEY_F3, MOD_MASK_NONE, "\033OR" , 0, 0, 0}, - { XKB_KEY_F3, /* F15 */ MOD_MASK_SHIFT, "\033[1;2R", 0, 0, 0}, - { XKB_KEY_F3, /* F27 */ MOD_MASK_CTRL, "\033[1;5R", 0, 0, 0}, - { XKB_KEY_F3, /* F39 */ MOD_MASK_LOGO, "\033[1;6R", 0, 0, 0}, - { XKB_KEY_F3, /* F51 */ MOD_MASK_ALT, "\033[1;3R", 0, 0, 0}, - { XKB_KEY_F4, MOD_MASK_NONE, "\033OS" , 0, 0, 0}, - { XKB_KEY_F4, /* F16 */ MOD_MASK_SHIFT, "\033[1;2S", 0, 0, 0}, - { XKB_KEY_F4, /* F28 */ MOD_MASK_CTRL, "\033[1;5S", 0, 0, 0}, - { XKB_KEY_F4, /* F40 */ MOD_MASK_LOGO, "\033[1;6S", 0, 0, 0}, - { XKB_KEY_F4, /* F52 */ MOD_MASK_ALT, "\033[1;3S", 0, 0, 0}, - { XKB_KEY_F5, MOD_MASK_NONE, "\033[15~", 0, 0, 0}, - { XKB_KEY_F5, /* F17 */ MOD_MASK_SHIFT, "\033[15;2~", 0, 0, 0}, - { XKB_KEY_F5, /* F29 */ MOD_MASK_CTRL, "\033[15;5~", 0, 0, 0}, - { XKB_KEY_F5, /* F41 */ MOD_MASK_LOGO, "\033[15;6~", 0, 0, 0}, - { XKB_KEY_F5, /* F53 */ MOD_MASK_ALT, "\033[15;3~", 0, 0, 0}, - { XKB_KEY_F6, MOD_MASK_NONE, "\033[17~", 0, 0, 0}, - { XKB_KEY_F6, /* F18 */ MOD_MASK_SHIFT, "\033[17;2~", 0, 0, 0}, - { XKB_KEY_F6, /* F30 */ MOD_MASK_CTRL, "\033[17;5~", 0, 0, 0}, - { XKB_KEY_F6, /* F42 */ MOD_MASK_LOGO, "\033[17;6~", 0, 0, 0}, - { XKB_KEY_F6, /* F54 */ MOD_MASK_ALT, "\033[17;3~", 0, 0, 0}, - { XKB_KEY_F7, MOD_MASK_NONE, "\033[18~", 0, 0, 0}, - { XKB_KEY_F7, /* F19 */ MOD_MASK_SHIFT, "\033[18;2~", 0, 0, 0}, - { XKB_KEY_F7, /* F31 */ MOD_MASK_CTRL, "\033[18;5~", 0, 0, 0}, - { XKB_KEY_F7, /* F43 */ MOD_MASK_LOGO, "\033[18;6~", 0, 0, 0}, - { XKB_KEY_F7, /* F55 */ MOD_MASK_ALT, "\033[18;3~", 0, 0, 0}, - { XKB_KEY_F8, MOD_MASK_NONE, "\033[19~", 0, 0, 0}, - { XKB_KEY_F8, /* F20 */ MOD_MASK_SHIFT, "\033[19;2~", 0, 0, 0}, - { XKB_KEY_F8, /* F32 */ MOD_MASK_CTRL, "\033[19;5~", 0, 0, 0}, - { XKB_KEY_F8, /* F44 */ MOD_MASK_LOGO, "\033[19;6~", 0, 0, 0}, - { XKB_KEY_F8, /* F56 */ MOD_MASK_ALT, "\033[19;3~", 0, 0, 0}, - { XKB_KEY_F9, MOD_MASK_NONE, "\033[20~", 0, 0, 0}, - { XKB_KEY_F9, /* F21 */ MOD_MASK_SHIFT, "\033[20;2~", 0, 0, 0}, - { XKB_KEY_F9, /* F33 */ MOD_MASK_CTRL, "\033[20;5~", 0, 0, 0}, - { XKB_KEY_F9, /* F45 */ MOD_MASK_LOGO, "\033[20;6~", 0, 0, 0}, - { XKB_KEY_F9, /* F57 */ MOD_MASK_ALT, "\033[20;3~", 0, 0, 0}, - { XKB_KEY_F10, MOD_MASK_NONE, "\033[21~", 0, 0, 0}, - { XKB_KEY_F10, /* F22 */ MOD_MASK_SHIFT, "\033[21;2~", 0, 0, 0}, - { XKB_KEY_F10, /* F34 */ MOD_MASK_CTRL, "\033[21;5~", 0, 0, 0}, - { XKB_KEY_F10, /* F46 */ MOD_MASK_LOGO, "\033[21;6~", 0, 0, 0}, - { XKB_KEY_F10, /* F58 */ MOD_MASK_ALT, "\033[21;3~", 0, 0, 0}, - { XKB_KEY_F11, MOD_MASK_NONE, "\033[23~", 0, 0, 0}, - { XKB_KEY_F11, /* F23 */ MOD_MASK_SHIFT, "\033[23;2~", 0, 0, 0}, - { XKB_KEY_F11, /* F35 */ MOD_MASK_CTRL, "\033[23;5~", 0, 0, 0}, - { XKB_KEY_F11, /* F47 */ MOD_MASK_LOGO, "\033[23;6~", 0, 0, 0}, - { XKB_KEY_F11, /* F59 */ MOD_MASK_ALT, "\033[23;3~", 0, 0, 0}, - { XKB_KEY_F12, MOD_MASK_NONE, "\033[24~", 0, 0, 0}, - { XKB_KEY_F12, /* F24 */ MOD_MASK_SHIFT, "\033[24;2~", 0, 0, 0}, - { XKB_KEY_F12, /* F36 */ MOD_MASK_CTRL, "\033[24;5~", 0, 0, 0}, - { XKB_KEY_F12, /* F48 */ MOD_MASK_LOGO, "\033[24;6~", 0, 0, 0}, - { XKB_KEY_F12, /* F60 */ MOD_MASK_ALT, "\033[24;3~", 0, 0, 0}, - { XKB_KEY_F13, MOD_MASK_NONE, "\033[1;2P", 0, 0, 0}, - { XKB_KEY_F14, MOD_MASK_NONE, "\033[1;2Q", 0, 0, 0}, - { XKB_KEY_F15, MOD_MASK_NONE, "\033[1;2R", 0, 0, 0}, - { XKB_KEY_F16, MOD_MASK_NONE, "\033[1;2S", 0, 0, 0}, - { XKB_KEY_F17, MOD_MASK_NONE, "\033[15;2~", 0, 0, 0}, - { XKB_KEY_F18, MOD_MASK_NONE, "\033[17;2~", 0, 0, 0}, - { XKB_KEY_F19, MOD_MASK_NONE, "\033[18;2~", 0, 0, 0}, - { XKB_KEY_F20, MOD_MASK_NONE, "\033[19;2~", 0, 0, 0}, - { XKB_KEY_F21, MOD_MASK_NONE, "\033[20;2~", 0, 0, 0}, - { XKB_KEY_F22, MOD_MASK_NONE, "\033[21;2~", 0, 0, 0}, - { XKB_KEY_F23, MOD_MASK_NONE, "\033[23;2~", 0, 0, 0}, - { XKB_KEY_F24, MOD_MASK_NONE, "\033[24;2~", 0, 0, 0}, - { XKB_KEY_F25, MOD_MASK_NONE, "\033[1;5P", 0, 0, 0}, - { XKB_KEY_F26, MOD_MASK_NONE, "\033[1;5Q", 0, 0, 0}, - { XKB_KEY_F27, MOD_MASK_NONE, "\033[1;5R", 0, 0, 0}, - { XKB_KEY_F28, MOD_MASK_NONE, "\033[1;5S", 0, 0, 0}, - { XKB_KEY_F29, MOD_MASK_NONE, "\033[15;5~", 0, 0, 0}, - { XKB_KEY_F30, MOD_MASK_NONE, "\033[17;5~", 0, 0, 0}, - { XKB_KEY_F31, MOD_MASK_NONE, "\033[18;5~", 0, 0, 0}, - { XKB_KEY_F32, MOD_MASK_NONE, "\033[19;5~", 0, 0, 0}, - { XKB_KEY_F33, MOD_MASK_NONE, "\033[20;5~", 0, 0, 0}, - { XKB_KEY_F34, MOD_MASK_NONE, "\033[21;5~", 0, 0, 0}, - { XKB_KEY_F35, MOD_MASK_NONE, "\033[23;5~", 0, 0, 0}, + /* keysym mask string appkey appcursor*/ + { XKB_KEY_KP_Home, MOD_MASK_SHIFT, "\033[2J", 0, -1}, + { XKB_KEY_KP_Home, MOD_MASK_SHIFT, "\033[1;2H", 0, +1}, + { XKB_KEY_KP_Home, MOD_MASK_ANY, "\033[H", 0, -1}, + { XKB_KEY_KP_Home, MOD_MASK_ANY, "\033[1~", 0, +1}, + { XKB_KEY_KP_Up, MOD_MASK_ANY, "\033Ox", +1, 0}, + { XKB_KEY_KP_Up, MOD_MASK_ANY, "\033[A", 0, -1}, + { XKB_KEY_KP_Up, MOD_MASK_ANY, "\033OA", 0, +1}, + { XKB_KEY_KP_Down, MOD_MASK_ANY, "\033Or", +1, 0}, + { XKB_KEY_KP_Down, MOD_MASK_ANY, "\033[B", 0, -1}, + { XKB_KEY_KP_Down, MOD_MASK_ANY, "\033OB", 0, +1}, + { XKB_KEY_KP_Left, MOD_MASK_ANY, "\033Ot", +1, 0}, + { XKB_KEY_KP_Left, MOD_MASK_ANY, "\033[D", 0, -1}, + { XKB_KEY_KP_Left, MOD_MASK_ANY, "\033OD", 0, +1}, + { XKB_KEY_KP_Right, MOD_MASK_ANY, "\033Ov", +1, 0}, + { XKB_KEY_KP_Right, MOD_MASK_ANY, "\033[C", 0, -1}, + { XKB_KEY_KP_Right, MOD_MASK_ANY, "\033OC", 0, +1}, + { XKB_KEY_KP_Prior, MOD_MASK_SHIFT, "\033[5;2~", 0, 0}, + { XKB_KEY_KP_Prior, MOD_MASK_ANY, "\033[5~", 0, 0}, + { XKB_KEY_KP_Begin, MOD_MASK_ANY, "\033[E", 0, 0}, + { XKB_KEY_KP_End, MOD_MASK_CTRL, "\033[J", -1, 0}, + { XKB_KEY_KP_End, MOD_MASK_CTRL, "\033[1;5F", +1, 0}, + { XKB_KEY_KP_End, MOD_MASK_SHIFT, "\033[K", -1, 0}, + { XKB_KEY_KP_End, MOD_MASK_SHIFT, "\033[1;2F", +1, 0}, + { XKB_KEY_KP_End, MOD_MASK_ANY, "\033[4~", 0, 0}, + { XKB_KEY_KP_Next, MOD_MASK_SHIFT, "\033[6;2~", 0, 0}, + { XKB_KEY_KP_Next, MOD_MASK_ANY, "\033[6~", 0, 0}, + { XKB_KEY_KP_Insert, MOD_MASK_SHIFT, "\033[2;2~", +1, 0}, + { XKB_KEY_KP_Insert, MOD_MASK_SHIFT, "\033[4l", -1, 0}, + { XKB_KEY_KP_Insert, MOD_MASK_CTRL, "\033[L", -1, 0}, + { XKB_KEY_KP_Insert, MOD_MASK_CTRL, "\033[2;5~", +1, 0}, + { XKB_KEY_KP_Insert, MOD_MASK_ANY, "\033[4h", -1, 0}, + { XKB_KEY_KP_Insert, MOD_MASK_ANY, "\033[2~", +1, 0}, + { XKB_KEY_KP_Delete, MOD_MASK_CTRL, "\033[M", -1, 0}, + { XKB_KEY_KP_Delete, MOD_MASK_CTRL, "\033[3;5~", +1, 0}, + { XKB_KEY_KP_Delete, MOD_MASK_SHIFT, "\033[2K", -1, 0}, + { XKB_KEY_KP_Delete, MOD_MASK_SHIFT, "\033[3;2~", +1, 0}, + { XKB_KEY_KP_Delete, MOD_MASK_ANY, "\033[P", -1, 0}, + { XKB_KEY_KP_Delete, MOD_MASK_ANY, "\033[3~", +1, 0}, + { XKB_KEY_KP_Multiply, MOD_MASK_ANY, "\033Oj", +2, 0}, + { XKB_KEY_KP_Add, MOD_MASK_ANY, "\033Ok", +2, 0}, + { XKB_KEY_KP_Enter, MOD_MASK_ANY, "\033OM", +2, 0}, + { XKB_KEY_KP_Enter, MOD_MASK_ANY, "\r", -1, 0}, + { XKB_KEY_KP_Enter, MOD_MASK_ANY, "\r\n", -1, 0}, + { XKB_KEY_KP_Subtract, MOD_MASK_ANY, "\033Om", +2, 0}, + { XKB_KEY_KP_Decimal, MOD_MASK_ANY, "\033On", +2, 0}, + { XKB_KEY_KP_Divide, MOD_MASK_ANY, "\033Oo", +2, 0}, + { XKB_KEY_KP_0, MOD_MASK_ANY, "\033Op", +2, 0}, + { XKB_KEY_KP_1, MOD_MASK_ANY, "\033Oq", +2, 0}, + { XKB_KEY_KP_2, MOD_MASK_ANY, "\033Or", +2, 0}, + { XKB_KEY_KP_3, MOD_MASK_ANY, "\033Os", +2, 0}, + { XKB_KEY_KP_4, MOD_MASK_ANY, "\033Ot", +2, 0}, + { XKB_KEY_KP_5, MOD_MASK_ANY, "\033Ou", +2, 0}, + { XKB_KEY_KP_6, MOD_MASK_ANY, "\033Ov", +2, 0}, + { XKB_KEY_KP_7, MOD_MASK_ANY, "\033Ow", +2, 0}, + { XKB_KEY_KP_8, MOD_MASK_ANY, "\033Ox", +2, 0}, + { XKB_KEY_KP_9, MOD_MASK_ANY, "\033Oy", +2, 0}, + { XKB_KEY_Up, MOD_MASK_SHIFT, "\033[1;2A", 0, 0}, + { XKB_KEY_Up, MOD_MASK_ALT, "\033[1;3A", 0, 0}, + { XKB_KEY_Up, MOD_MASK_SHIFT|MOD_MASK_ALT,"\033[1;4A", 0, 0}, + { XKB_KEY_Up, MOD_MASK_CTRL, "\033[1;5A", 0, 0}, + { XKB_KEY_Up,MOD_MASK_SHIFT|MOD_MASK_CTRL,"\033[1;6A", 0, 0}, + { XKB_KEY_Up, MOD_MASK_CTRL|MOD_MASK_ALT,"\033[1;7A", 0, 0}, + { XKB_KEY_Up,MOD_MASK_SHIFT|MOD_MASK_CTRL|MOD_MASK_ALT,"\033[1;8A",0,0}, + { XKB_KEY_Up, MOD_MASK_ANY, "\033[A", 0, -1}, + { XKB_KEY_Up, MOD_MASK_ANY, "\033OA", 0, +1}, + { XKB_KEY_Down, MOD_MASK_SHIFT, "\033[1;2B", 0, 0}, + { XKB_KEY_Down, MOD_MASK_ALT, "\033[1;3B", 0, 0}, + { XKB_KEY_Down,MOD_MASK_SHIFT|MOD_MASK_ALT,"\033[1;4B", 0, 0}, + { XKB_KEY_Down, MOD_MASK_CTRL, "\033[1;5B", 0, 0}, + { XKB_KEY_Down,MOD_MASK_SHIFT|MOD_MASK_CTRL,"\033[1;6B", 0, 0}, + { XKB_KEY_Down,MOD_MASK_CTRL|MOD_MASK_ALT,"\033[1;7B", 0, 0}, + { XKB_KEY_Down,MOD_MASK_SHIFT|MOD_MASK_CTRL|MOD_MASK_ALT,"\033[1;8B",0,0}, + { XKB_KEY_Down, MOD_MASK_ANY, "\033[B", 0, -1}, + { XKB_KEY_Down, MOD_MASK_ANY, "\033OB", 0, +1}, + { XKB_KEY_Left, MOD_MASK_SHIFT, "\033[1;2D", 0, 0}, + { XKB_KEY_Left, MOD_MASK_ALT, "\033[1;3D", 0, 0}, + { XKB_KEY_Left,MOD_MASK_SHIFT|MOD_MASK_ALT,"\033[1;4D", 0, 0}, + { XKB_KEY_Left, MOD_MASK_CTRL, "\033[1;5D", 0, 0}, + { XKB_KEY_Left,MOD_MASK_SHIFT|MOD_MASK_CTRL,"\033[1;6D", 0, 0}, + { XKB_KEY_Left,MOD_MASK_CTRL|MOD_MASK_ALT,"\033[1;7D", 0, 0}, + { XKB_KEY_Left,MOD_MASK_SHIFT|MOD_MASK_CTRL|MOD_MASK_ALT,"\033[1;8D",0,0}, + { XKB_KEY_Left, MOD_MASK_ANY, "\033[D", 0, -1}, + { XKB_KEY_Left, MOD_MASK_ANY, "\033OD", 0, +1}, + { XKB_KEY_Right, MOD_MASK_SHIFT, "\033[1;2C", 0, 0}, + { XKB_KEY_Right, MOD_MASK_ALT, "\033[1;3C", 0, 0}, + { XKB_KEY_Right,MOD_MASK_SHIFT|MOD_MASK_ALT,"\033[1;4C", 0, 0}, + { XKB_KEY_Right, MOD_MASK_CTRL, "\033[1;5C", 0, 0}, + { XKB_KEY_Right,MOD_MASK_SHIFT|MOD_MASK_CTRL,"\033[1;6C", 0, 0}, + { XKB_KEY_Right,MOD_MASK_CTRL|MOD_MASK_ALT,"\033[1;7C", 0, 0}, + { XKB_KEY_Right,MOD_MASK_SHIFT|MOD_MASK_CTRL|MOD_MASK_ALT,"\033[1;8C",0,0}, + { XKB_KEY_Right, MOD_MASK_ANY, "\033[C", 0, -1}, + { XKB_KEY_Right, MOD_MASK_ANY, "\033OC", 0, +1}, + { XKB_KEY_ISO_Left_Tab, MOD_MASK_SHIFT, "\033[Z", 0, 0}, + { XKB_KEY_Return, MOD_MASK_ALT, "\033\r", 0, 0}, + { XKB_KEY_Return, MOD_MASK_ALT, "\033\r\n", 0, 0}, + { XKB_KEY_Return, MOD_MASK_ANY, "\r", 0, 0}, + { XKB_KEY_Return, MOD_MASK_ANY, "\r\n", 0, 0}, + { XKB_KEY_Insert, MOD_MASK_SHIFT, "\033[4l", -1, 0}, + { XKB_KEY_Insert, MOD_MASK_SHIFT, "\033[2;2~", +1, 0}, + { XKB_KEY_Insert, MOD_MASK_CTRL, "\033[L", -1, 0}, + { XKB_KEY_Insert, MOD_MASK_CTRL, "\033[2;5~", +1, 0}, + { XKB_KEY_Insert, MOD_MASK_ANY, "\033[4h", -1, 0}, + { XKB_KEY_Insert, MOD_MASK_ANY, "\033[2~", +1, 0}, + { XKB_KEY_Delete, MOD_MASK_CTRL, "\033[M", -1, 0}, + { XKB_KEY_Delete, MOD_MASK_CTRL, "\033[3;5~", +1, 0}, + { XKB_KEY_Delete, MOD_MASK_SHIFT, "\033[2K", -1, 0}, + { XKB_KEY_Delete, MOD_MASK_SHIFT, "\033[3;2~", +1, 0}, + { XKB_KEY_Delete, MOD_MASK_ANY, "\033[P", -1, 0}, + { XKB_KEY_Delete, MOD_MASK_ANY, "\033[3~", +1, 0}, + { XKB_KEY_BackSpace, MOD_MASK_NONE, "\177", 0, 0}, + { XKB_KEY_BackSpace, MOD_MASK_CTRL, "\033\177", 0, 0}, + { XKB_KEY_Home, MOD_MASK_SHIFT, "\033[2J", 0, -1}, + { XKB_KEY_Home, MOD_MASK_SHIFT, "\033[1;2H", 0, +1}, + { XKB_KEY_Home, MOD_MASK_ANY, "\033[H", 0, -1}, + { XKB_KEY_Home, MOD_MASK_ANY, "\033[1~", 0, +1}, + { XKB_KEY_End, MOD_MASK_CTRL, "\033[J", -1, 0}, + { XKB_KEY_End, MOD_MASK_CTRL, "\033[1;5F", +1, 0}, + { XKB_KEY_End, MOD_MASK_SHIFT, "\033[K", -1, 0}, + { XKB_KEY_End, MOD_MASK_SHIFT, "\033[1;2F", +1, 0}, + { XKB_KEY_End, MOD_MASK_ANY, "\033[4~", 0, 0}, + { XKB_KEY_Prior, MOD_MASK_CTRL, "\033[5;5~", 0, 0}, + { XKB_KEY_Prior, MOD_MASK_SHIFT, "\033[5;2~", 0, 0}, + { XKB_KEY_Next, MOD_MASK_SHIFT, "\033[6;2~", 0, 0}, + { XKB_KEY_Next, MOD_MASK_ANY, "\033[6~", 0, 0}, + { XKB_KEY_F1, MOD_MASK_NONE, "\033OP" , 0, 0}, + { XKB_KEY_F1, /* F13 */ MOD_MASK_SHIFT, "\033[1;2P", 0, 0}, + { XKB_KEY_F1, /* F25 */ MOD_MASK_CTRL, "\033[1;5P", 0, 0}, + { XKB_KEY_F1, /* F37 */ MOD_MASK_LOGO, "\033[1;6P", 0, 0}, + { XKB_KEY_F1, /* F49 */ MOD_MASK_ALT, "\033[1;3P", 0, 0}, + { XKB_KEY_F2, MOD_MASK_NONE, "\033OQ" , 0, 0}, + { XKB_KEY_F2, /* F14 */ MOD_MASK_SHIFT, "\033[1;2Q", 0, 0}, + { XKB_KEY_F2, /* F26 */ MOD_MASK_CTRL, "\033[1;5Q", 0, 0}, + { XKB_KEY_F2, /* F38 */ MOD_MASK_LOGO, "\033[1;6Q", 0, 0}, + { XKB_KEY_F2, /* F50 */ MOD_MASK_ALT, "\033[1;3Q", 0, 0}, + { XKB_KEY_F3, MOD_MASK_NONE, "\033OR" , 0, 0}, + { XKB_KEY_F3, /* F15 */ MOD_MASK_SHIFT, "\033[1;2R", 0, 0}, + { XKB_KEY_F3, /* F27 */ MOD_MASK_CTRL, "\033[1;5R", 0, 0}, + { XKB_KEY_F3, /* F39 */ MOD_MASK_LOGO, "\033[1;6R", 0, 0}, + { XKB_KEY_F3, /* F51 */ MOD_MASK_ALT, "\033[1;3R", 0, 0}, + { XKB_KEY_F4, MOD_MASK_NONE, "\033OS" , 0, 0}, + { XKB_KEY_F4, /* F16 */ MOD_MASK_SHIFT, "\033[1;2S", 0, 0}, + { XKB_KEY_F4, /* F28 */ MOD_MASK_CTRL, "\033[1;5S", 0, 0}, + { XKB_KEY_F4, /* F40 */ MOD_MASK_LOGO, "\033[1;6S", 0, 0}, + { XKB_KEY_F4, /* F52 */ MOD_MASK_ALT, "\033[1;3S", 0, 0}, + { XKB_KEY_F5, MOD_MASK_NONE, "\033[15~", 0, 0}, + { XKB_KEY_F5, /* F17 */ MOD_MASK_SHIFT, "\033[15;2~", 0, 0}, + { XKB_KEY_F5, /* F29 */ MOD_MASK_CTRL, "\033[15;5~", 0, 0}, + { XKB_KEY_F5, /* F41 */ MOD_MASK_LOGO, "\033[15;6~", 0, 0}, + { XKB_KEY_F5, /* F53 */ MOD_MASK_ALT, "\033[15;3~", 0, 0}, + { XKB_KEY_F6, MOD_MASK_NONE, "\033[17~", 0, 0}, + { XKB_KEY_F6, /* F18 */ MOD_MASK_SHIFT, "\033[17;2~", 0, 0}, + { XKB_KEY_F6, /* F30 */ MOD_MASK_CTRL, "\033[17;5~", 0, 0}, + { XKB_KEY_F6, /* F42 */ MOD_MASK_LOGO, "\033[17;6~", 0, 0}, + { XKB_KEY_F6, /* F54 */ MOD_MASK_ALT, "\033[17;3~", 0, 0}, + { XKB_KEY_F7, MOD_MASK_NONE, "\033[18~", 0, 0}, + { XKB_KEY_F7, /* F19 */ MOD_MASK_SHIFT, "\033[18;2~", 0, 0}, + { XKB_KEY_F7, /* F31 */ MOD_MASK_CTRL, "\033[18;5~", 0, 0}, + { XKB_KEY_F7, /* F43 */ MOD_MASK_LOGO, "\033[18;6~", 0, 0}, + { XKB_KEY_F7, /* F55 */ MOD_MASK_ALT, "\033[18;3~", 0, 0}, + { XKB_KEY_F8, MOD_MASK_NONE, "\033[19~", 0, 0}, + { XKB_KEY_F8, /* F20 */ MOD_MASK_SHIFT, "\033[19;2~", 0, 0}, + { XKB_KEY_F8, /* F32 */ MOD_MASK_CTRL, "\033[19;5~", 0, 0}, + { XKB_KEY_F8, /* F44 */ MOD_MASK_LOGO, "\033[19;6~", 0, 0}, + { XKB_KEY_F8, /* F56 */ MOD_MASK_ALT, "\033[19;3~", 0, 0}, + { XKB_KEY_F9, MOD_MASK_NONE, "\033[20~", 0, 0}, + { XKB_KEY_F9, /* F21 */ MOD_MASK_SHIFT, "\033[20;2~", 0, 0}, + { XKB_KEY_F9, /* F33 */ MOD_MASK_CTRL, "\033[20;5~", 0, 0}, + { XKB_KEY_F9, /* F45 */ MOD_MASK_LOGO, "\033[20;6~", 0, 0}, + { XKB_KEY_F9, /* F57 */ MOD_MASK_ALT, "\033[20;3~", 0, 0}, + { XKB_KEY_F10, MOD_MASK_NONE, "\033[21~", 0, 0}, + { XKB_KEY_F10, /* F22 */ MOD_MASK_SHIFT, "\033[21;2~", 0, 0}, + { XKB_KEY_F10, /* F34 */ MOD_MASK_CTRL, "\033[21;5~", 0, 0}, + { XKB_KEY_F10, /* F46 */ MOD_MASK_LOGO, "\033[21;6~", 0, 0}, + { XKB_KEY_F10, /* F58 */ MOD_MASK_ALT, "\033[21;3~", 0, 0}, + { XKB_KEY_F11, MOD_MASK_NONE, "\033[23~", 0, 0}, + { XKB_KEY_F11, /* F23 */ MOD_MASK_SHIFT, "\033[23;2~", 0, 0}, + { XKB_KEY_F11, /* F35 */ MOD_MASK_CTRL, "\033[23;5~", 0, 0}, + { XKB_KEY_F11, /* F47 */ MOD_MASK_LOGO, "\033[23;6~", 0, 0}, + { XKB_KEY_F11, /* F59 */ MOD_MASK_ALT, "\033[23;3~", 0, 0}, + { XKB_KEY_F12, MOD_MASK_NONE, "\033[24~", 0, 0}, + { XKB_KEY_F12, /* F24 */ MOD_MASK_SHIFT, "\033[24;2~", 0, 0}, + { XKB_KEY_F12, /* F36 */ MOD_MASK_CTRL, "\033[24;5~", 0, 0}, + { XKB_KEY_F12, /* F48 */ MOD_MASK_LOGO, "\033[24;6~", 0, 0}, + { XKB_KEY_F12, /* F60 */ MOD_MASK_ALT, "\033[24;3~", 0, 0}, + { XKB_KEY_F13, MOD_MASK_NONE, "\033[1;2P", 0, 0}, + { XKB_KEY_F14, MOD_MASK_NONE, "\033[1;2Q", 0, 0}, + { XKB_KEY_F15, MOD_MASK_NONE, "\033[1;2R", 0, 0}, + { XKB_KEY_F16, MOD_MASK_NONE, "\033[1;2S", 0, 0}, + { XKB_KEY_F17, MOD_MASK_NONE, "\033[15;2~", 0, 0}, + { XKB_KEY_F18, MOD_MASK_NONE, "\033[17;2~", 0, 0}, + { XKB_KEY_F19, MOD_MASK_NONE, "\033[18;2~", 0, 0}, + { XKB_KEY_F20, MOD_MASK_NONE, "\033[19;2~", 0, 0}, + { XKB_KEY_F21, MOD_MASK_NONE, "\033[20;2~", 0, 0}, + { XKB_KEY_F22, MOD_MASK_NONE, "\033[21;2~", 0, 0}, + { XKB_KEY_F23, MOD_MASK_NONE, "\033[23;2~", 0, 0}, + { XKB_KEY_F24, MOD_MASK_NONE, "\033[24;2~", 0, 0}, + { XKB_KEY_F25, MOD_MASK_NONE, "\033[1;5P", 0, 0}, + { XKB_KEY_F26, MOD_MASK_NONE, "\033[1;5Q", 0, 0}, + { XKB_KEY_F27, MOD_MASK_NONE, "\033[1;5R", 0, 0}, + { XKB_KEY_F28, MOD_MASK_NONE, "\033[1;5S", 0, 0}, + { XKB_KEY_F29, MOD_MASK_NONE, "\033[15;5~", 0, 0}, + { XKB_KEY_F30, MOD_MASK_NONE, "\033[17;5~", 0, 0}, + { XKB_KEY_F31, MOD_MASK_NONE, "\033[18;5~", 0, 0}, + { XKB_KEY_F32, MOD_MASK_NONE, "\033[19;5~", 0, 0}, + { XKB_KEY_F33, MOD_MASK_NONE, "\033[20;5~", 0, 0}, + { XKB_KEY_F34, MOD_MASK_NONE, "\033[21;5~", 0, 0}, + { XKB_KEY_F35, MOD_MASK_NONE, "\033[23;5~", 0, 0}, }; /* diff --git a/st.c b/st.c index 922eda0..0c1f1d3 100644 --- a/st.c +++ b/st.c @@ -42,6 +42,7 @@ #define STR_ARG_SIZ ESC_ARG_SIZ /* macros */ +#define IS_SET(flag) ((term.mode & (flag)) != 0) #define NUMMAXLEN(x) ((int)(sizeof(x) * 2.56 + 0.5) + 1) #define ISCONTROLC0(c) (BETWEEN(c, 0, 0x1f) || (c) == '\177') #define ISCONTROLC1(c) (BETWEEN(c, 0x80, 0x9f)) @@ -49,7 +50,18 @@ #define ISDELIM(u) (utf8strchr(worddelimiters, u) != NULL) /* constants */ -#define ISO14755CMD "dmenu -p codepoint: 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 @@ -954,8 +994,6 @@ tnew(int col, int row) { term = (Term){ .c = { .attr = { .fg = defaultfg, .bg = defaultbg } } }; tresize(col, row); - term.numlock = 1; - treset(); } @@ -1391,20 +1429,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); @@ -1424,36 +1458,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); // Removed in wayland version - MODBIT(term.mode, 0, MODE_MOUSE); - MODBIT(term.mode, set, MODE_MOUSEX10); + // xsetpointermotion(0); // Disabled in wayland branch + xsetmode(0, MODE_MOUSE); + xsetmode(set, MODE_MOUSEX10); break; case 1000: /* 1000: report button press */ - // xsetpointermotion(0); // Removed in wayland version - MODBIT(term.mode, 0, MODE_MOUSE); - MODBIT(term.mode, set, MODE_MOUSEBTN); + // xsetpointermotion(0); // Disabled in wayland branch + xsetmode(0, MODE_MOUSE); + xsetmode(set, MODE_MOUSEBTN); break; case 1002: /* 1002: report motion on button press */ - // xsetpointermotion(0); // Removed in wayland version - MODBIT(term.mode, 0, MODE_MOUSE); - MODBIT(term.mode, set, MODE_MOUSEMOTION); + // xsetpointermotion(0); // Disabled in wayland branch + xsetmode(0, MODE_MOUSE); + xsetmode(set, MODE_MOUSEMOTION); break; case 1003: /* 1003: enable all mouse motions */ - // xsetpointermotion(0); // Removed in wayland version - MODBIT(term.mode, 0, MODE_MOUSE); - MODBIT(term.mode, set, MODE_MOUSEMANY); + // xsetpointermotion(set); // Disabled in wayland branch + 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) @@ -1478,7 +1512,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 @@ -1499,8 +1533,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); @@ -1718,7 +1752,7 @@ csihandle(void) case ' ': switch (csiescseq.mode[1]) { case 'q': /* DECSCUSR -- Set Cursor Style */ - if (wlsetcursor(csiescseq.arg[0])) + if (xsetcursor(csiescseq.arg[0])) goto unknown; break; default: @@ -1775,7 +1809,7 @@ strhandle(void) case 1: case 2: if (narg > 1) - wlsettitle(strescseq.args[1]); + xsettitle(strescseq.args[1]); return; case 52: if (narg > 2) { @@ -1783,8 +1817,8 @@ strhandle(void) dec = base64dec(strescseq.args[2]); if (dec) { - wlsetsel(dec); - wlclipcopy(); + xsetsel(dec); + xclipcopy(); } else { fprintf(stderr, "erresc: invalid base64\n"); } @@ -1797,7 +1831,7 @@ strhandle(void) /* FALLTHROUGH */ case 104: /* color reset, here p = NULL */ j = (narg > 1) ? atoi(strescseq.args[1]) : -1; - if (wlsetcolorname(j, p)) { + if (xsetcolorname(j, p)) { fprintf(stderr, "erresc: invalid color %s\n", p); } else { /* @@ -1810,7 +1844,7 @@ strhandle(void) } break; case 'k': /* old title set compatibility */ - wlsettitle(strescseq.args[0]); + xsettitle(strescseq.args[0]); return; case 'P': /* DCS -- Device Control String */ term.mode |= ESC_DCS; @@ -2205,13 +2239,13 @@ eschandle(uchar ascii) case 'c': /* RIS -- Reset to inital state */ treset(); resettitle(); - wlloadcols(); + 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); @@ -2495,18 +2529,35 @@ tresize(int col, int row) void resettitle(void) { - wlsettitle(NULL); + xsettitle(NULL); } void -redraw(void) +drawregion(int x1, int y1, int x2, int y2) { - tfulldirt(); - // draw(); // removed in wayland branch + int y; + for (y = y1; y < y2; y++) { + if (!term.dirty[y]) + continue; + + term.dirty[y] = 0; + xdrawline(term.line[y], x1, y, x2); + } +} + +void +draw(void) +{ + if (!xstartdraw()) + return; + drawregion(0, 0, term.col, term.row); + xdrawcursor(); + xfinishdraw(); } void -numlock(const Arg *dummy) +redraw(void) { - term.numlock ^= 1; + tfulldirt(); + // draw(); // disabled in wayland branch } diff --git a/st.h b/st.h index 9466692..cf6bf90 100644 --- a/st.h +++ b/st.h @@ -13,7 +13,6 @@ #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))) @@ -37,34 +36,6 @@ enum glyph_attribute { ATTR_BOLD_FAINT = ATTR_BOLD | ATTR_FAINT, }; -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 selection_mode { SEL_IDLE = 0, SEL_EMPTY = 1, @@ -119,7 +90,6 @@ 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; @@ -129,7 +99,7 @@ typedef struct { int w, h; /* window width and height */ int ch; /* char height */ int cw; /* char width */ - char state; /* focus, redraw, visible */ + int mode; /* window state/mode flags */ int cursor; /* cursor style */ } TermWindow; @@ -160,9 +130,9 @@ typedef union { void die(const char *, ...); void redraw(void); +void draw(void); void iso14755(const Arg *); -void numlock(const Arg *); void printscreen(const Arg *); void printsel(const Arg *); void sendbreak(const Arg *); diff --git a/win.h b/win.h index 7b9b961..d4975a8 100644 --- a/win.h +++ b/win.h @@ -1,17 +1,41 @@ /* See LICENSE for license details. */ -void draw(void); -void drawregion(int, int, int, int); +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, +}; // void xbell(int); -void wlclipcopy(void); +void xclipcopy(void); +void xdrawcursor(void); +void xdrawline(Line, int, int, int); // void xhints(void); -void wlloadcols(void); -int wlsetcolorname(int, const char*); -void wlsettitle(char *); -int wlsetcursor(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 wlselpaste(void); -void wlsetsel(char*); +void xsetsel(char*); +int xstartdraw(void); void wlneeddraw(void); diff --git a/wl.c b/wl.c index 9019c6f..2bb5813 100644 --- a/wl.c +++ b/wl.c @@ -51,7 +51,6 @@ typedef struct { /* 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; typedef struct { @@ -74,6 +73,7 @@ typedef struct { /* 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 *); @@ -82,6 +82,9 @@ static void zoomreset(const Arg *); /* config.h for applying patches and the configuration. */ #include "config.h" +/* Macros */ +#define IS_SET(flag) ((win.mode & (flag)) != 0) + typedef struct { struct xkb_context *ctx; struct xkb_keymap *keymap; @@ -166,6 +169,7 @@ typedef struct { /* TODO: Categorize these */ +static void wlselpaste(void); static int x2col(int); static int y2row(int); static int match(uint, uint); @@ -223,7 +227,6 @@ static void wlclear(int, int, int, int); static void wldraws(char *, Glyph, int, int, int, int); static void wldrawglyph(Glyph, int, int); static void wlloadcursor(void); -static void wldrawcursor(void); static void regglobal(void *, struct wl_registry *, uint32_t, const char *, uint32_t); @@ -275,11 +278,6 @@ static struct wl_data_source_listener datasrclistener = { datasrctarget, datasrcsend, datasrccancelled }; static struct wl_data_offer_listener dataofferlistener = { dataofferoffer }; -enum window_state { - WIN_VISIBLE = 1, - WIN_FOCUSED = 2 -}; - /* Font Ring Cache */ enum { FRC_NORMAL, @@ -310,8 +308,23 @@ static char *opt_line = NULL; static char *opt_name = NULL; static char *opt_title = NULL; +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(); +} + +void +numlock(const Arg *dummy) +{ + win.mode ^= MODE_NUMLOCK; +} + int -wlsetcursor(int cursor) +xsetcursor(int cursor) { DEFAULT(cursor, 1); if (!BETWEEN(cursor, 0, 6)) @@ -369,15 +382,12 @@ kmap(xkb_keysym_t k, uint state) if (IS_SET(MODE_APPKEYPAD) ? kp->appkey < 0 : kp->appkey > 0) continue; - if (term.numlock && kp->appkey == 2) + if (IS_SET(MODE_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; } @@ -434,7 +444,7 @@ zoomreset(const Arg *arg) } void -wlclipcopy(void) +xclipcopy(void) { clipcopy(NULL); } @@ -458,7 +468,7 @@ selpaste(const Arg * dummy) } void -wlsetsel(char * buf) +xsetsel(char * buf) { setsel(buf, wl.globalserial); } @@ -776,7 +786,7 @@ void kbdenter(void *data, struct wl_keyboard *keyboard, uint32_t serial, struct wl_surface *surface, struct wl_array *keys) { - win.state |= WIN_FOCUSED; + win.mode |= MODE_FOCUSED; if (IS_SET(MODE_FOCUS)) ttywrite("\033[I", 3, 0); /* need to redraw the cursor */ @@ -789,7 +799,7 @@ kbdleave(void *data, struct wl_keyboard *keyboard, uint32_t serial, { /* selection offers are invalidated when we lose keyboard focus */ wl.seloffer = NULL; - win.state &= ~WIN_FOCUSED; + win.mode &= ~MODE_FOCUSED; if (IS_SET(MODE_FOCUS)) ttywrite("\033[O", 3, 0); /* need to redraw the cursor */ @@ -919,7 +929,7 @@ wlresize(int col, int row) } void -wlsettitle(char *title) +xsettitle(char *title) { DEFAULT(title, "st-wl"); xdg_toplevel_set_title(wl.xdgtoplevel, title); @@ -929,15 +939,15 @@ void surfenter(void *data, struct wl_surface *surface, struct wl_output *output) { wl.vis++; - if (!(win.state & WIN_VISIBLE)) - win.state |= WIN_VISIBLE; + if (!(IS_SET(MODE_VISIBLE))) + win.mode |= MODE_VISIBLE; } void surfleave(void *data, struct wl_surface *surface, struct wl_output *output) { if (--wl.vis == 0) - win.state &= ~WIN_VISIBLE; + win.mode &= ~MODE_VISIBLE; } void @@ -945,7 +955,7 @@ framedone(void *data, struct wl_callback *callback, uint32_t msecs) { wl_callback_destroy(callback); wl.framecb = NULL; - if (wl.needdraw && win.state & WIN_VISIBLE) { + if (wl.needdraw && IS_SET(MODE_VISIBLE)) { draw(); } } @@ -1008,7 +1018,7 @@ wlloadcolor(int i, const char *name, uint32_t *color) } void -wlloadcols(void) +xloadcols(void) { int i; @@ -1025,7 +1035,7 @@ wlloadcols(void) } int -wlsetcolorname(int x, const char *name) +xsetcolorname(int x, const char *name) { uint32_t color; @@ -1217,8 +1227,8 @@ wlneeddraw(void) wl.needdraw = true; } -void -draw(void) +int +xstartdraw(void) { int y, y0; @@ -1231,7 +1241,49 @@ draw(void) } wld_set_target_buffer(wld.renderer, wld.buffer); - drawregion(0, 0, term.col, term.row); + + return 1; // Should be IS_SET(MODE_VISIBLE), but this results in no window. + // TODO: Implement proper MODE_VISIBLE handling. +} + +void +xdrawline(Line line, int x1, int y, int x2) +{ + int ic, ib, x, ox; + Glyph base, new; + char buf[DRAW_BUF_SIZ]; + + //if (!term.dirty[y]) // TODO: Check out why this must be commented out + // return; + + term.dirty[y] = 0; + base = term.line[y][0]; + ic = ib = ox = 0; + for (x = x1; x < x2; x++) { + new = term.line[y][x]; + if (new.mode == ATTR_WDUMMY) + continue; + if (selected(x, y)) + new.mode ^= ATTR_REVERSE; + if (ib > 0 && (ATTRCMP(base, new) || ib >= DRAW_BUF_SIZ-UTF_SIZ)) { + wldraws(buf, base, ox, y, ic, ib); + ic = ib = 0; + } + if (ib == 0) { + ox = x; + base = new; + } + + ib += utf8encode(new.u, buf+ib); + ic += (new.mode & ATTR_WIDE)? 2 : 1; + } + if (ib > 0) + wldraws(buf, base, ox, y, ic, ib); +} + +void +xfinishdraw(void) +{ wl.framecb = wl_surface_frame(wl.surface); wl_callback_add_listener(wl.framecb, &framelistener, NULL); wld_flush(wld.renderer); @@ -1246,45 +1298,6 @@ draw(void) wl.needdraw = false; } -void -drawregion(int x1, int y1, int x2, int y2) -{ - int ic, ib, x, y, ox; - Glyph base, new; - char buf[DRAW_BUF_SIZ]; - - for (y = y1; y < y2; y++) { - if (!term.dirty[y]) - continue; - - term.dirty[y] = 0; - base = term.line[y][0]; - ic = ib = ox = 0; - for (x = x1; x < x2; x++) { - new = term.line[y][x]; - if (new.mode == ATTR_WDUMMY) - continue; - if (selected(x, y)) - new.mode ^= ATTR_REVERSE; - if (ib > 0 && (ATTRCMP(base, new) - || ib >= DRAW_BUF_SIZ-UTF_SIZ)) { - wldraws(buf, base, ox, y, ic, ib); - ic = ib = 0; - } - if (ib == 0) { - ox = x; - base = new; - } - - ib += utf8encode(new.u, buf+ib); - ic += (new.mode & ATTR_WIDE)? 2 : 1; - } - if (ib > 0) - wldraws(buf, base, ox, y, ic, ib); - } - wldrawcursor(); -} - /* * Absolute coordinates. */ @@ -1394,7 +1407,7 @@ wldraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) | ((fg & 0xff) / 2); } - if (base.mode & ATTR_BLINK && term.mode & MODE_BLINK) + if (base.mode & ATTR_BLINK && win.mode & MODE_BLINK) fg = bg; if (base.mode & ATTR_INVISIBLE) @@ -1563,7 +1576,7 @@ wlloadcursor(void) } void -wldrawcursor(void) +xdrawcursor(void) { static int oldx = 0, oldy = 0; int curx; @@ -1620,7 +1633,7 @@ wldrawcursor(void) return; /* draw the new one */ - if (win.state & WIN_FOCUSED) { + if (IS_SET(MODE_FOCUSED)) { switch (win.cursor) { case 7: /* st-wl extension: snowman */ utf8decode("☃", &g.u, UTF_SIZ); @@ -1814,7 +1827,7 @@ wlinit(void) wld.fontctx = wld_font_create_context(); wlloadfonts(usedfont, 0); - wlloadcols(); + xloadcols(); wlloadcursor(); wl.vis = 0; @@ -1833,6 +1846,8 @@ wlinit(void) wl_surface_commit(wl.surface); wl.xkb.ctx = xkb_context_new(0); + + win.mode = MODE_NUMLOCK; resettitle(); wlsel.tclick1 = 0; @@ -1874,7 +1889,7 @@ run(void) if (blinktimeout) { blinkset = tattrset(ATTR_BLINK); if (!blinkset) - MODBIT(term.mode, 0, MODE_BLINK); + MODBIT(win.mode, 0, MODE_BLINK); } } @@ -1889,7 +1904,7 @@ run(void) if (blinkset && blinktimeout) { if (TIMEDIFF(now, lastblink) >= blinktimeout) { tsetdirtattr(ATTR_BLINK); - term.mode ^= MODE_BLINK; + win.mode ^= MODE_BLINK; lastblink = now; } else { msecs = MIN(msecs, blinktimeout - \ @@ -1910,7 +1925,7 @@ run(void) } } - if (wl.needdraw && win.state & WIN_VISIBLE) { + if (wl.needdraw && IS_SET(MODE_VISIBLE)) { if (!wl.framecb) { draw(); } From 4fdd3252cbc0f19f73b4342437359af26eed48f3 Mon Sep 17 00:00:00 2001 From: ian <42294085+ianbeyst@users.noreply.github.com> Date: Fri, 14 Jun 2019 20:35:38 +0200 Subject: [PATCH 125/129] pre-merge changes up until st upstream commit 20e0da7 --- config.def.h | 2 +- st.c | 114 ++++++++++++++++++++++++--------- st.h | 68 ++------------------ win.h | 7 +- wl.c | 177 ++++++++++++++++++++++++--------------------------- x.c | 1 + 6 files changed, 178 insertions(+), 191 deletions(-) diff --git a/config.def.h b/config.def.h index b83512d..ae34198 100644 --- a/config.def.h +++ b/config.def.h @@ -16,7 +16,7 @@ static int borderpx = 2; * 4: value of shell in /etc/passwd * 5: value of shell in config.h */ -char *shell = "/bin/sh"; +static char *shell = "/bin/sh"; char *utmp = NULL; char *stty_args = "stty raw pass8 nl -echo -iexten -cstopb 38400"; diff --git a/st.c b/st.c index f2a80a2..542dc53 100644 --- a/st.c +++ b/st.c @@ -3,24 +3,17 @@ #include #include #include -#include #include #include #include #include #include #include -#include #include #include -#include -#include #include #include -#include -#include #include -#include #include #include "st.h" @@ -36,7 +29,6 @@ /* Arbitrary sizes */ #define UTF_INVALID 0xFFFD -// #define ESC_BUF_SIZ (128*UTF_SIZ) // Required in st-wl.h #define ESC_ARG_SIZ 16 #define STR_BUF_SIZ ESC_BUF_SIZ #define STR_ARG_SIZ ESC_ARG_SIZ @@ -95,6 +87,51 @@ enum escape_state { ESC_DCS =128, }; +typedef struct { + Glyph attr; /* current char attributes */ + int x; + int y; + char state; +} TCursor; + +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; + + int alt; +} Selection; + +/* 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 */ + char trantbl[4]; /* charset table translation */ + int charset; /* current charset */ + int icharset; /* selected charset for sequence */ + int *tabs; +} Term; + /* CSI Escape sequence structs */ /* ESC '[' [[ [] [;]] []] */ typedef struct { @@ -116,8 +153,7 @@ typedef struct { int narg; /* nb of args */ } STREscape; - -static void execsh(char **); +static void execsh(char *, char **); static void stty(char **); static void sigchld(int); static void ttywriteraw(const char *, size_t); @@ -168,28 +204,28 @@ static void tstrsequence(uchar); static void drawregion(int, int, int, int); +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 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); /* Globals */ -Term term; -int cmdfd; -pid_t pid; -int oldbutton = 3; /* button event on startup: 3 = release */ - +static Term term; static Selection sel; static CSIEscape csiescseq; static STREscape strescseq; static int iofd = 1; +static int cmdfd; +static pid_t pid; static uchar utfbyte[UTF_SIZ + 1] = {0x80, 0, 0xC0, 0xE0, 0xF0}; static uchar utfmask[UTF_SIZ + 1] = {0xC0, 0x80, 0xE0, 0xF0, 0xF8}; @@ -607,7 +643,7 @@ getsel(void) * The best solution seems like to produce '\n' when * something is copied from st and convert '\n' to * '\r', when something to be pasted is received by - * st-wl. + * st. * FIXME: Fix the computer world. */ if ((y < sel.ne.y || lastx >= linelen) && !(last->mode & ATTR_WRAP)) @@ -639,7 +675,7 @@ die(const char *errstr, ...) } void -execsh(char **args) +execsh(char *cmd, char **args) { char *sh, *prog; const struct passwd *pw; @@ -653,7 +689,7 @@ execsh(char **args) } if ((sh = getenv("SHELL")) == NULL) - sh = (pw->pw_shell[0]) ? pw->pw_shell : shell; + sh = (pw->pw_shell[0]) ? pw->pw_shell : cmd; if (args) prog = args[0]; @@ -725,8 +761,8 @@ stty(char **args) perror("Couldn't call stty"); } -void -ttynew(char *line, char *out, char **args) +int +ttynew(char *line, char *cmd, char *out, char **args) { int m, s; @@ -745,7 +781,7 @@ ttynew(char *line, char *out, char **args) die("open line failed: %s\n", strerror(errno)); dup2(cmdfd, 0); stty(args); - return; + return cmdfd; } /* seems to work fine on linux, openbsd and freebsd */ @@ -766,7 +802,7 @@ ttynew(char *line, char *out, char **args) die("ioctl TIOCSCTTY failed: %s\n", strerror(errno)); close(s); close(m); - execsh(args); + execsh(cmd, args); break; default: close(s); @@ -774,6 +810,7 @@ ttynew(char *line, char *out, char **args) signal(SIGCHLD, sigchld); break; } + return cmdfd; } size_t @@ -897,6 +934,13 @@ ttyresize(int tw, int th) fprintf(stderr, "Couldn't set window size: %s\n", strerror(errno)); } +void +ttyhangup() +{ + /* Send SIGHUP to shell */ + kill(pid, SIGHUP); +} + int tattrset(int attr) { @@ -1649,7 +1693,6 @@ csihandle(void) tputtab(csiescseq.arg[0]); break; case 'J': /* ED -- Clear screen */ - selclear(); switch (csiescseq.arg[0]) { case 0: /* below */ tclearregion(term.c.x, term.c.y, term.col-1, term.c.y); @@ -1817,8 +1860,8 @@ strhandle(void) dec = base64dec(strescseq.args[2]); if (dec) { - xsetsel(dec); - xclipcopy(); + xsetsel(dec); + xclipcopy(); } else { fprintf(stderr, "erresc: invalid base64\n"); } @@ -2105,7 +2148,7 @@ tcontrolcode(uchar ascii) /* backwards compatibility to xterm */ strhandle(); } else { - xbell(); + xbell(); } break; case '\033': /* ESC */ @@ -2317,7 +2360,7 @@ tputc(Rune u) if (strescseq.len+len >= sizeof(strescseq.buf)-1) { /* * Here is a bug in terminals. If the user never sends - * some code to stop the str or esc command, then st-wl + * some code to stop the str or esc command, then st * will stop responding. But this is better than * silently failing with unknown characters. At least * then users will report back. @@ -2547,10 +2590,23 @@ drawregion(int x1, int y1, int x2, int y2) void draw(void) { + int cx = term.c.x; + if (!xstartdraw()) return; + + /* 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--; + drawregion(0, 0, term.col, term.row); - xdrawcursor(); + 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 cf6bf90..371df19 100644 --- a/st.h +++ b/st.h @@ -1,8 +1,12 @@ /* See LICENSE for license details. */ +#include +#include + /* Arbitrary sizes */ #define UTF_SIZ 4 #define ESC_BUF_SIZ (128*UTF_SIZ) + /* macros */ #define MIN(a, b) ((a) < (b) ? (a) : (b)) #define MAX(a, b) ((a) < (b) ? (b) : (a)) @@ -68,59 +72,6 @@ typedef struct { typedef Glyph *Line; -typedef struct { - Glyph attr; /* current char attributes */ - int x; - int y; - char state; -} TCursor; - -/* Internal representation of the screen */ -typedef struct { - int row; /* nb row */ - int col; /* nb col */ - Line *line; /* screen */ - Line *alt; /* alternate screen */ - int *dirty; /* dirtyness of lines */ - TCursor c; /* cursor */ - int top; /* top scroll limit */ - int bot; /* bottom scroll limit */ - int mode; /* terminal mode flags */ - int esc; /* escape state flags */ - char trantbl[4]; /* charset table translation */ - int charset; /* current charset */ - int icharset; /* selected charset for sequence */ - int *tabs; -} Term; - -/* 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 mode; /* window state/mode flags */ - int cursor; /* cursor style */ -} TermWindow; - -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; - - int alt; -} Selection; - typedef union { int i; uint ui; @@ -142,7 +93,8 @@ int tattrset(int); void tnew(int, int); void tresize(int, int); void tsetdirtattr(int); -void ttynew(char *, char *, char **); +void ttyhangup(void); +int ttynew(char *, char *, char *, char **); size_t ttyread(void); void ttyresize(int, int); void ttywrite(const char *, size_t, int); @@ -153,7 +105,6 @@ void selclear(void); void selinit(void); void selstart(int, int, int); void selextend(int, int, int, int); -void selnormalize(void); int selected(int, int); char *getsel(void); @@ -164,14 +115,7 @@ void *xmalloc(size_t); void *xrealloc(void *, size_t); char *xstrdup(char *); -/* Globals */ -extern Term term; -extern int cmdfd; -extern pid_t pid; -extern int oldbutton; - /* config.h globals */ -extern char *shell; extern char *utmp; extern char *stty_args; extern char *vtiden; diff --git a/win.h b/win.h index d893ca7..0358977 100644 --- a/win.h +++ b/win.h @@ -25,17 +25,16 @@ enum win_mode { void xbell(void); void xclipcopy(void); -void xdrawcursor(void); +void xdrawcursor(int, int, Glyph, int, int, Glyph); void xdrawline(Line, int, int, int); -void xhints(void); void xfinishdraw(void); void xloadcols(void); -int xsetcolorname(int, const char*); +int xsetcolorname(int, const char *); void xsettitle(char *); int xsetcursor(int); void xsetmode(int, unsigned int); void xsetpointermotion(int); -void xsetsel(char*); +void xsetsel(char *); int xstartdraw(void); void wlneeddraw(void); diff --git a/wl.c b/wl.c index aadb6ae..c49a931 100644 --- a/wl.c +++ b/wl.c @@ -1,8 +1,8 @@ /* See LICENSE for license details. */ #include +#include #include #include -#include #include #include #include @@ -85,6 +85,16 @@ static void zoomreset(const Arg *); /* Macros */ #define IS_SET(flag) ((win.mode & (flag)) != 0) +/* 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 mode; /* window state/mode flags */ + int cursor; /* cursor style */ +} TermWindow; + typedef struct { struct xkb_context *ctx; struct xkb_keymap *keymap; @@ -170,11 +180,12 @@ typedef struct { /* TODO: Categorize these */ static void wlselpaste(void); -static int x2col(int); -static int y2row(int); +static int evcol(int); +static int evrow(int); static int match(uint, uint); static char *kmap(xkb_keysym_t, uint); static void wlresize(int, int); +static void wlinit(int, int); static void cresize(int, int); static void wlloadfonts(char *, double); static void wlunloadfonts(void); @@ -308,6 +319,8 @@ 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 xbell(void) { @@ -346,21 +359,19 @@ xsetcursor(int cursor) } int -x2col(int x) +evcol(int x) { x -= borderpx; - x /= win.cw; - - return LIMIT(x, 0, term.col-1); + LIMIT(x, 0, win.tw - 1); + return x / win.cw; } int -y2row(int y) +evrow(int y) { y -= borderpx; - y /= win.ch; - - return LIMIT(y, 0, term.row-1); + LIMIT(y, 0, win.th - 1); + return y / win.ch; } int @@ -498,7 +509,7 @@ mousesel(int done) } } - selextend(x2col(wl.px), y2row(wl.py), seltype, done); + selextend(evcol(wl.px), evrow(wl.py), seltype, done); if (done) setsel(getsel(), wl.globalserial); } @@ -562,7 +573,7 @@ wlmousereportbutton(uint32_t button, uint32_t state) void wlmousereportmotion(wl_fixed_t fx, wl_fixed_t fy) { - int x = x2col(wl_fixed_to_int(fx)), y = y2row(wl_fixed_to_int(fy)); + int x = evcol(wl_fixed_to_int(fx)), y = evrow(wl_fixed_to_int(fy)); if (x == oldx && y == oldy) return; @@ -665,7 +676,7 @@ ptrbutton(void * data, struct wl_pointer * pointer, uint32_t serial, wlsel.tclick2 = wlsel.tclick1; wlsel.tclick1 = time; - selstart(x2col(wl.px), y2row(wl.py), snap); + selstart(evcol(wl.px), evrow(wl.py), snap); } break; } @@ -993,7 +1004,8 @@ void xdgtoplevelclose(void *data, struct xdg_toplevel *toplevel) { /* Send SIGHUP to shell */ - kill(pid, SIGHUP); + pid_t thispid = getpid(); + kill(thispid, SIGHUP); exit(0); } @@ -1242,16 +1254,6 @@ wlneeddraw(void) int xstartdraw(void) { - int y, y0; - - for (y = 0; y <= term.bot; ++y) { - if (!term.dirty[y]) - continue; - for (y0 = y; y <= term.bot && term.dirty[y]; ++y); - wl_surface_damage(wl.surface, 0, borderpx + y0 * win.ch, - win.w, (y - y0) * win.ch); - } - wld_set_target_buffer(wld.renderer, wld.buffer); return 1; // Should be IS_SET(MODE_VISIBLE), but this results in no window. @@ -1265,14 +1267,10 @@ xdrawline(Line line, int x1, int y, int x2) Glyph base, new; char buf[DRAW_BUF_SIZ]; - //if (!term.dirty[y]) // TODO: Check out why this must be commented out - // return; - - term.dirty[y] = 0; - base = term.line[y][0]; + base = line[0]; ic = ib = ox = 0; for (x = x1; x < x2; x++) { - new = term.line[y][x]; + new = line[x]; if (new.mode == ATTR_WDUMMY) continue; if (selected(x, y)) @@ -1290,7 +1288,9 @@ xdrawline(Line line, int x1, int y, int x2) ic += (new.mode & ATTR_WIDE)? 2 : 1; } if (ib > 0) - wldraws(buf, base, ox, y, ic, ib); + wldraws(buf, base, ox, y, ic, ib); + + wl_surface_damage(wl.surface, 0, borderpx + y * win.ch, win.w, win.ch); } void @@ -1428,15 +1428,15 @@ wldraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) /* Intelligent cleaning up of the borders. */ if (x == 0) { wlclear(0, (y == 0)? 0 : winy, borderpx, - ((y >= term.row-1)? win.h : (winy + win.ch))); + ((winy + win.ch >= borderpx + win.th)? win.h : (winy + win.ch))); } - if (x + charlen >= term.col) { + if (winx + width >= borderpx + win.tw) { wlclear(winx + width, (y == 0)? 0 : winy, win.w, - ((y >= term.row-1)? win.h : (winy + win.ch))); + ((winy + win.ch >= borderpx + win.th)? win.h : (winy + win.ch))); } if (y == 0) wlclear(winx, 0, winx + width, borderpx); - if (y == term.row-1) + if (winy + win.ch >= borderpx + win.th) wlclear(winx, winy + win.ch, winx + width, win.h); /* Clean up the region we want to draw to. */ @@ -1588,43 +1588,32 @@ wlloadcursor(void) } void -xdrawcursor(void) +xdrawcursor(int cx, int cy, Glyph g, int ox, int oy, Glyph og) { - static int oldx = 0, oldy = 0; - int curx; - Glyph g = {' ', ATTR_NULL, defaultbg, defaultcs}, og; uint32_t 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 (selected(oldx, oldy)) + /* remove the old cursor */ + if (selected(ox, oy)) og.mode ^= ATTR_REVERSE; - wldrawglyph(og, oldx, oldy); - if (oldx != curx || oldy != term.c.y) { - wl_surface_damage(wl.surface, borderpx + oldx * win.cw, - borderpx + oldy * win.ch, win.cw, win.ch); - } + wldrawglyph(og, ox, oy); - g.u = term.line[term.c.y][term.c.x].u; + 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 (ox != cx || oy != cy) { + wl_surface_damage(wl.surface, borderpx + ox * win.cw, + borderpx + oy * win.ch, win.cw, win.ch); + } + if (IS_SET(MODE_REVERSE)) { g.mode |= ATTR_REVERSE; g.bg = defaultfg; - if (selected(term.c.x, term.c.y)) { + if (selected(cx, cy)) { drawcol = dc.col[defaultcs]; g.fg = defaultrcs; } else { @@ -1632,66 +1621,61 @@ xdrawcursor(void) g.fg = defaultcs; } } else { - if (selected(term.c.x, term.c.y)) { - drawcol = dc.col[defaultrcs]; + if (selected(cx, cy)) { g.fg = defaultfg; g.bg = defaultrcs; } else { - drawcol = dc.col[defaultcs]; + g.fg = defaultbg; + g.bg = defaultrcs; } + drawcol = dc.col[g.bg]; } - if (IS_SET(MODE_HIDE)) - return; - /* draw the new one */ if (IS_SET(MODE_FOCUSED)) { switch (win.cursor) { case 7: /* st-wl extension: snowman */ - utf8decode("☃", &g.u, UTF_SIZ); + g.u = 0x2603; case 0: /* Blinking Block */ case 1: /* Blinking Block (Default) */ case 2: /* Steady Block */ - g.mode |= term.line[term.c.y][curx].mode & ATTR_WIDE; - wldrawglyph(g, term.c.x, term.c.y); + wldrawglyph(g, cx, cy); break; case 3: /* Blinking Underline */ case 4: /* Steady Underline */ wld_fill_rectangle(wld.renderer, drawcol, - borderpx + curx * win.cw, - borderpx + (term.c.y + 1) * win.ch - \ - cursorthickness, + borderpx + cx * win.cw, + borderpx + (cy + 1) * win.ch - cursorthickness, win.cw, cursorthickness); break; case 5: /* Blinking bar */ case 6: /* Steady bar */ wld_fill_rectangle(wld.renderer, drawcol, - borderpx + curx * win.cw, - borderpx + term.c.y * win.ch, + borderpx + cx * win.cw, + borderpx + cy * win.ch, cursorthickness, win.ch); break; } } else { wld_fill_rectangle(wld.renderer, drawcol, - borderpx + curx * win.cw, - borderpx + term.c.y * win.ch, + borderpx + cx * win.cw, + borderpx + cy * win.ch, win.cw - 1, 1); wld_fill_rectangle(wld.renderer, drawcol, - borderpx + curx * win.cw, - borderpx + term.c.y * win.ch, + borderpx + cx * win.cw, + borderpx + cy * win.ch, 1, win.ch - 1); wld_fill_rectangle(wld.renderer, drawcol, - borderpx + (curx + 1) * win.cw - 1, - borderpx + term.c.y * win.ch, + borderpx + (cx + 1) * win.cw - 1, + borderpx + cy * win.ch, 1, win.ch - 1); wld_fill_rectangle(wld.renderer, drawcol, - borderpx + curx * win.cw, - borderpx + (term.c.y + 1) * win.ch - 1, + borderpx + cx * win.cw, + borderpx + (cy + 1) * win.ch - 1, win.cw, 1); } - wl_surface_damage(wl.surface, borderpx + curx * win.cw, - borderpx + term.c.y * win.ch, win.cw, win.ch); - oldx = curx, oldy = term.c.y; + wl_surface_damage(wl.surface, borderpx + cx * win.cw, + borderpx + cy * win.ch, win.cw, win.ch); } void @@ -1799,7 +1783,7 @@ datasrccancelled(void *data, struct wl_data_source *source) } void -wlinit(void) +wlinit(int cols, int rows) { struct wl_registry *registry; @@ -1843,8 +1827,8 @@ wlinit(void) wlloadcursor(); wl.vis = 0; - win.h = 2 * borderpx + term.row * win.ch; - win.w = 2 * borderpx + term.col * win.cw; + win.h = 2 * borderpx + rows * win.ch; + win.w = 2 * borderpx + cols * win.cw; wl.surface = wl_compositor_create_surface(wl.cmp); wl_surface_add_listener(wl.surface, &surflistener, NULL); @@ -1873,12 +1857,13 @@ run(void) { fd_set rfd; int wlfd = wl_display_get_fd(wl.dpy), blinkset = 0; + int ttyfd; struct timespec drawtimeout, *tv = NULL, now, last, lastblink; ulong msecs; /* Look for initial configure. */ wl_display_roundtrip(wl.dpy); - ttynew(opt_line, opt_io, opt_cmd); + ttyfd = ttynew(opt_line, shell, opt_io, opt_cmd); cresize(win.w, win.h); draw(); @@ -1887,16 +1872,16 @@ run(void) for (;;) { FD_ZERO(&rfd); - FD_SET(cmdfd, &rfd); + FD_SET(ttyfd, &rfd); FD_SET(wlfd, &rfd); - if (pselect(MAX(wlfd, cmdfd)+1, &rfd, NULL, NULL, tv, NULL) < 0) { + if (pselect(MAX(wlfd, ttyfd)+1, &rfd, NULL, NULL, tv, NULL) < 0) { if (errno == EINTR) continue; die("select failed: %s\n", strerror(errno)); } - if (FD_ISSET(cmdfd, &rfd)) { + if (FD_ISSET(ttyfd, &rfd)) { ttyread(); if (blinktimeout) { blinkset = tattrset(ATTR_BLINK); @@ -2019,8 +2004,10 @@ main(int argc, char *argv[]) opt_title = basename(xstrdup(argv[0])); } setlocale(LC_CTYPE, ""); - tnew(MAX(cols, 1), MAX(rows, 1)); - wlinit(); + cols = MAX(cols, 1); + rows = MAX(rows, 1); + tnew(cols, rows); + wlinit(cols, rows); selinit(); run(); diff --git a/x.c b/x.c index 96944ee..3fbd14c 100644 --- a/x.c +++ b/x.c @@ -1,5 +1,6 @@ /* See LICENSE for license details. */ #include +#include #include #include #include From c6c40a4e0abae98d95ec808b5b3ae7ecd339c235 Mon Sep 17 00:00:00 2001 From: ian <42294085+ianbeyst@users.noreply.github.com> Date: Sat, 15 Jun 2019 12:55:11 +0200 Subject: [PATCH 126/129] pre-merge changes up until upstream st commit caa1d8f --- config.def.h | 531 ++++++++++++++++++++++++++------------------------- st.c | 107 ++++------- st.h | 3 +- win.h | 1 - wl.c | 61 +++--- 5 files changed, 342 insertions(+), 361 deletions(-) diff --git a/config.def.h b/config.def.h index ae34198..b4ad8a6 100644 --- a/config.def.h +++ b/config.def.h @@ -30,9 +30,9 @@ static float chscale = 1.0; /* * word delimiter string * - * More advanced example: " `'\"()[]{}" + * More advanced example: L" `'\"()[]{}" */ -char *worddelimiters = " "; +wchar_t *worddelimiters = L" "; /* selection timeouts (in milliseconds) */ static unsigned int doubleclicktimeout = 300; @@ -62,7 +62,6 @@ static unsigned int cursorthickness = 2; */ static int bellvolume = 0; - /* default TERM value */ char *termname = "st-wl-256color"; @@ -73,43 +72,43 @@ char *termname = "st-wl-256color"; * the st-wl.info and appropriately install the st-wl.info in the environment * where you use this st-wl version. * - * it#$tabspaces, + * 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 + * stty tabs */ 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", + /* 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", }; @@ -154,14 +153,14 @@ static unsigned int defaultattr = 11; * Beware that overloading Button1 will disable the selection. */ static MouseShortcut mshortcuts[] = { - /* button mask string */ - { -1, MOD_MASK_NONE, "" } + /* button mask string */ + { -1, MOD_MASK_NONE, "" } }; static Axiskey ashortcuts[] = { - /* axis direction mask string */ - { AXIS_VERTICAL, +1, MOD_MASK_ANY, "\031"}, - { AXIS_VERTICAL, -1, MOD_MASK_ANY, "\005"}, + /* axis direction mask string */ + { AXIS_VERTICAL, +1, MOD_MASK_ANY, "\031"}, + { AXIS_VERTICAL, -1, MOD_MASK_ANY, "\005"}, }; /* Internal keyboard shortcuts. */ @@ -169,23 +168,23 @@ static Axiskey ashortcuts[] = { #define TERMMOD (MOD_MASK_CTRL|MOD_MASK_SHIFT) static Shortcut shortcuts[] = { - /* modifier key function argument */ - { MOD_MASK_ANY, XKB_KEY_Break, sendbreak, {.i = 0} }, - { MOD_MASK_CTRL, XKB_KEY_Print, toggleprinter, {.i = 0} }, - { MOD_MASK_SHIFT, XKB_KEY_Print, printscreen, {.i = 0} }, - { MOD_MASK_ANY, XKB_KEY_Print, printsel, {.i = 0} }, - { TERMMOD, XKB_KEY_Prior, zoom, {.f = +1} }, - { TERMMOD, XKB_KEY_Next, zoom, {.f = -1} }, - { TERMMOD, XKB_KEY_Home, zoomreset, {.f = 0} }, - { TERMMOD, XKB_KEY_C, clipcopy, {.i = 0} }, - { TERMMOD, XKB_KEY_V, clippaste, {.i = 0} }, - { TERMMOD, XKB_KEY_Y, selpaste, {.i = 0} }, - { TERMMOD, XKB_KEY_Num_Lock, numlock, {.i = 0} }, - { TERMMOD, XKB_KEY_I, iso14755, {.i = 0} }, + /* mask keysym function argument */ + { MOD_MASK_ANY, XKB_KEY_Break, sendbreak, {.i = 0} }, + { MOD_MASK_CTRL, XKB_KEY_Print, toggleprinter, {.i = 0} }, + { MOD_MASK_SHIFT, XKB_KEY_Print, printscreen, {.i = 0} }, + { MOD_MASK_ANY, XKB_KEY_Print, printsel, {.i = 0} }, + { TERMMOD, XKB_KEY_Prior, zoom, {.f = +1} }, + { TERMMOD, XKB_KEY_Next, zoom, {.f = -1} }, + { TERMMOD, XKB_KEY_Home, zoomreset, {.f = 0} }, + { TERMMOD, XKB_KEY_C, clipcopy, {.i = 0} }, + { TERMMOD, XKB_KEY_V, clippaste, {.i = 0} }, + { TERMMOD, XKB_KEY_Y, selpaste, {.i = 0} }, + { MOD_MASK_SHIFT, XKB_KEY_Insert, selpaste, {.i = 0} }, + { TERMMOD, XKB_KEY_Num_Lock, numlock, {.i = 0} }, }; /* - * Special keys (change & recompile st-wl.info accordingly) + * Special keys (change & recompile st.info accordingly) * * Mask value: * * Use MOD_MASK_ANY to match the key no matter modifiers state @@ -204,7 +203,7 @@ static Shortcut shortcuts[] = { * * > 0: crlf mode is enabled * * < 0: crlf mode is disabled * - * Be careful with the order of the definitions because st-wl searches in + * Be careful with the order of the definitions because st searches in * this table sequentially, so any MOD_MASK_ANY must be in the last * position for a key. */ @@ -215,13 +214,16 @@ static Shortcut shortcuts[] = { */ static xkb_keysym_t mappedkeys[] = { -1 }; -/* State bits to ignore when matching key or button events. */ +/* + * State bits to ignore when matching key or button events. By default, + * numlock (Mod2Mask) and keyboard layout (XKB_KEY_SWITCH_MOD) are ignored. + */ static uint ignoremod = 0; /* * Override mouse-select while mask is active (when MODE_MOUSE is set). - * Note that if you want to use MOD_MASK_SHIFT with selmasks, set this to an - * other modifier, set to 0 to not use it. + * Note that if you want to use MOD_MASK_SHIFT with selmasks, set this to an other + * modifier, set to 0 to not use it. */ static uint forceselmod = MOD_MASK_SHIFT; @@ -230,214 +232,213 @@ static uint forceselmod = MOD_MASK_SHIFT; * world. Please decide about changes wisely. */ static Key key[] = { - /* keysym mask string appkey appcursor*/ - { XKB_KEY_KP_Home, MOD_MASK_SHIFT, "\033[2J", 0, -1}, - { XKB_KEY_KP_Home, MOD_MASK_SHIFT, "\033[1;2H", 0, +1}, - { XKB_KEY_KP_Home, MOD_MASK_ANY, "\033[H", 0, -1}, - { XKB_KEY_KP_Home, MOD_MASK_ANY, "\033[1~", 0, +1}, - { XKB_KEY_KP_Up, MOD_MASK_ANY, "\033Ox", +1, 0}, - { XKB_KEY_KP_Up, MOD_MASK_ANY, "\033[A", 0, -1}, - { XKB_KEY_KP_Up, MOD_MASK_ANY, "\033OA", 0, +1}, - { XKB_KEY_KP_Down, MOD_MASK_ANY, "\033Or", +1, 0}, - { XKB_KEY_KP_Down, MOD_MASK_ANY, "\033[B", 0, -1}, - { XKB_KEY_KP_Down, MOD_MASK_ANY, "\033OB", 0, +1}, - { XKB_KEY_KP_Left, MOD_MASK_ANY, "\033Ot", +1, 0}, - { XKB_KEY_KP_Left, MOD_MASK_ANY, "\033[D", 0, -1}, - { XKB_KEY_KP_Left, MOD_MASK_ANY, "\033OD", 0, +1}, - { XKB_KEY_KP_Right, MOD_MASK_ANY, "\033Ov", +1, 0}, - { XKB_KEY_KP_Right, MOD_MASK_ANY, "\033[C", 0, -1}, - { XKB_KEY_KP_Right, MOD_MASK_ANY, "\033OC", 0, +1}, - { XKB_KEY_KP_Prior, MOD_MASK_SHIFT, "\033[5;2~", 0, 0}, - { XKB_KEY_KP_Prior, MOD_MASK_ANY, "\033[5~", 0, 0}, - { XKB_KEY_KP_Begin, MOD_MASK_ANY, "\033[E", 0, 0}, - { XKB_KEY_KP_End, MOD_MASK_CTRL, "\033[J", -1, 0}, - { XKB_KEY_KP_End, MOD_MASK_CTRL, "\033[1;5F", +1, 0}, - { XKB_KEY_KP_End, MOD_MASK_SHIFT, "\033[K", -1, 0}, - { XKB_KEY_KP_End, MOD_MASK_SHIFT, "\033[1;2F", +1, 0}, - { XKB_KEY_KP_End, MOD_MASK_ANY, "\033[4~", 0, 0}, - { XKB_KEY_KP_Next, MOD_MASK_SHIFT, "\033[6;2~", 0, 0}, - { XKB_KEY_KP_Next, MOD_MASK_ANY, "\033[6~", 0, 0}, - { XKB_KEY_KP_Insert, MOD_MASK_SHIFT, "\033[2;2~", +1, 0}, - { XKB_KEY_KP_Insert, MOD_MASK_SHIFT, "\033[4l", -1, 0}, - { XKB_KEY_KP_Insert, MOD_MASK_CTRL, "\033[L", -1, 0}, - { XKB_KEY_KP_Insert, MOD_MASK_CTRL, "\033[2;5~", +1, 0}, - { XKB_KEY_KP_Insert, MOD_MASK_ANY, "\033[4h", -1, 0}, - { XKB_KEY_KP_Insert, MOD_MASK_ANY, "\033[2~", +1, 0}, - { XKB_KEY_KP_Delete, MOD_MASK_CTRL, "\033[M", -1, 0}, - { XKB_KEY_KP_Delete, MOD_MASK_CTRL, "\033[3;5~", +1, 0}, - { XKB_KEY_KP_Delete, MOD_MASK_SHIFT, "\033[2K", -1, 0}, - { XKB_KEY_KP_Delete, MOD_MASK_SHIFT, "\033[3;2~", +1, 0}, - { XKB_KEY_KP_Delete, MOD_MASK_ANY, "\033[P", -1, 0}, - { XKB_KEY_KP_Delete, MOD_MASK_ANY, "\033[3~", +1, 0}, - { XKB_KEY_KP_Multiply, MOD_MASK_ANY, "\033Oj", +2, 0}, - { XKB_KEY_KP_Add, MOD_MASK_ANY, "\033Ok", +2, 0}, - { XKB_KEY_KP_Enter, MOD_MASK_ANY, "\033OM", +2, 0}, - { XKB_KEY_KP_Enter, MOD_MASK_ANY, "\r", -1, 0}, - { XKB_KEY_KP_Enter, MOD_MASK_ANY, "\r\n", -1, 0}, - { XKB_KEY_KP_Subtract, MOD_MASK_ANY, "\033Om", +2, 0}, - { XKB_KEY_KP_Decimal, MOD_MASK_ANY, "\033On", +2, 0}, - { XKB_KEY_KP_Divide, MOD_MASK_ANY, "\033Oo", +2, 0}, - { XKB_KEY_KP_0, MOD_MASK_ANY, "\033Op", +2, 0}, - { XKB_KEY_KP_1, MOD_MASK_ANY, "\033Oq", +2, 0}, - { XKB_KEY_KP_2, MOD_MASK_ANY, "\033Or", +2, 0}, - { XKB_KEY_KP_3, MOD_MASK_ANY, "\033Os", +2, 0}, - { XKB_KEY_KP_4, MOD_MASK_ANY, "\033Ot", +2, 0}, - { XKB_KEY_KP_5, MOD_MASK_ANY, "\033Ou", +2, 0}, - { XKB_KEY_KP_6, MOD_MASK_ANY, "\033Ov", +2, 0}, - { XKB_KEY_KP_7, MOD_MASK_ANY, "\033Ow", +2, 0}, - { XKB_KEY_KP_8, MOD_MASK_ANY, "\033Ox", +2, 0}, - { XKB_KEY_KP_9, MOD_MASK_ANY, "\033Oy", +2, 0}, - { XKB_KEY_Up, MOD_MASK_SHIFT, "\033[1;2A", 0, 0}, - { XKB_KEY_Up, MOD_MASK_ALT, "\033[1;3A", 0, 0}, - { XKB_KEY_Up, MOD_MASK_SHIFT|MOD_MASK_ALT,"\033[1;4A", 0, 0}, - { XKB_KEY_Up, MOD_MASK_CTRL, "\033[1;5A", 0, 0}, - { XKB_KEY_Up,MOD_MASK_SHIFT|MOD_MASK_CTRL,"\033[1;6A", 0, 0}, - { XKB_KEY_Up, MOD_MASK_CTRL|MOD_MASK_ALT,"\033[1;7A", 0, 0}, - { XKB_KEY_Up,MOD_MASK_SHIFT|MOD_MASK_CTRL|MOD_MASK_ALT,"\033[1;8A",0,0}, - { XKB_KEY_Up, MOD_MASK_ANY, "\033[A", 0, -1}, - { XKB_KEY_Up, MOD_MASK_ANY, "\033OA", 0, +1}, - { XKB_KEY_Down, MOD_MASK_SHIFT, "\033[1;2B", 0, 0}, - { XKB_KEY_Down, MOD_MASK_ALT, "\033[1;3B", 0, 0}, - { XKB_KEY_Down,MOD_MASK_SHIFT|MOD_MASK_ALT,"\033[1;4B", 0, 0}, - { XKB_KEY_Down, MOD_MASK_CTRL, "\033[1;5B", 0, 0}, - { XKB_KEY_Down,MOD_MASK_SHIFT|MOD_MASK_CTRL,"\033[1;6B", 0, 0}, - { XKB_KEY_Down,MOD_MASK_CTRL|MOD_MASK_ALT,"\033[1;7B", 0, 0}, - { XKB_KEY_Down,MOD_MASK_SHIFT|MOD_MASK_CTRL|MOD_MASK_ALT,"\033[1;8B",0,0}, - { XKB_KEY_Down, MOD_MASK_ANY, "\033[B", 0, -1}, - { XKB_KEY_Down, MOD_MASK_ANY, "\033OB", 0, +1}, - { XKB_KEY_Left, MOD_MASK_SHIFT, "\033[1;2D", 0, 0}, - { XKB_KEY_Left, MOD_MASK_ALT, "\033[1;3D", 0, 0}, - { XKB_KEY_Left,MOD_MASK_SHIFT|MOD_MASK_ALT,"\033[1;4D", 0, 0}, - { XKB_KEY_Left, MOD_MASK_CTRL, "\033[1;5D", 0, 0}, - { XKB_KEY_Left,MOD_MASK_SHIFT|MOD_MASK_CTRL,"\033[1;6D", 0, 0}, - { XKB_KEY_Left,MOD_MASK_CTRL|MOD_MASK_ALT,"\033[1;7D", 0, 0}, - { XKB_KEY_Left,MOD_MASK_SHIFT|MOD_MASK_CTRL|MOD_MASK_ALT,"\033[1;8D",0,0}, - { XKB_KEY_Left, MOD_MASK_ANY, "\033[D", 0, -1}, - { XKB_KEY_Left, MOD_MASK_ANY, "\033OD", 0, +1}, - { XKB_KEY_Right, MOD_MASK_SHIFT, "\033[1;2C", 0, 0}, - { XKB_KEY_Right, MOD_MASK_ALT, "\033[1;3C", 0, 0}, - { XKB_KEY_Right,MOD_MASK_SHIFT|MOD_MASK_ALT,"\033[1;4C", 0, 0}, - { XKB_KEY_Right, MOD_MASK_CTRL, "\033[1;5C", 0, 0}, - { XKB_KEY_Right,MOD_MASK_SHIFT|MOD_MASK_CTRL,"\033[1;6C", 0, 0}, - { XKB_KEY_Right,MOD_MASK_CTRL|MOD_MASK_ALT,"\033[1;7C", 0, 0}, - { XKB_KEY_Right,MOD_MASK_SHIFT|MOD_MASK_CTRL|MOD_MASK_ALT,"\033[1;8C",0,0}, - { XKB_KEY_Right, MOD_MASK_ANY, "\033[C", 0, -1}, - { XKB_KEY_Right, MOD_MASK_ANY, "\033OC", 0, +1}, - { XKB_KEY_ISO_Left_Tab, MOD_MASK_SHIFT, "\033[Z", 0, 0}, - { XKB_KEY_Return, MOD_MASK_ALT, "\033\r", 0, 0}, - { XKB_KEY_Return, MOD_MASK_ALT, "\033\r\n", 0, 0}, - { XKB_KEY_Return, MOD_MASK_ANY, "\r", 0, 0}, - { XKB_KEY_Return, MOD_MASK_ANY, "\r\n", 0, 0}, - { XKB_KEY_Insert, MOD_MASK_SHIFT, "\033[4l", -1, 0}, - { XKB_KEY_Insert, MOD_MASK_SHIFT, "\033[2;2~", +1, 0}, - { XKB_KEY_Insert, MOD_MASK_CTRL, "\033[L", -1, 0}, - { XKB_KEY_Insert, MOD_MASK_CTRL, "\033[2;5~", +1, 0}, - { XKB_KEY_Insert, MOD_MASK_ANY, "\033[4h", -1, 0}, - { XKB_KEY_Insert, MOD_MASK_ANY, "\033[2~", +1, 0}, - { XKB_KEY_Delete, MOD_MASK_CTRL, "\033[M", -1, 0}, - { XKB_KEY_Delete, MOD_MASK_CTRL, "\033[3;5~", +1, 0}, - { XKB_KEY_Delete, MOD_MASK_SHIFT, "\033[2K", -1, 0}, - { XKB_KEY_Delete, MOD_MASK_SHIFT, "\033[3;2~", +1, 0}, - { XKB_KEY_Delete, MOD_MASK_ANY, "\033[P", -1, 0}, - { XKB_KEY_Delete, MOD_MASK_ANY, "\033[3~", +1, 0}, - { XKB_KEY_BackSpace, MOD_MASK_NONE, "\177", 0, 0}, - { XKB_KEY_BackSpace, MOD_MASK_CTRL, "\033\177", 0, 0}, - { XKB_KEY_Home, MOD_MASK_SHIFT, "\033[2J", 0, -1}, - { XKB_KEY_Home, MOD_MASK_SHIFT, "\033[1;2H", 0, +1}, - { XKB_KEY_Home, MOD_MASK_ANY, "\033[H", 0, -1}, - { XKB_KEY_Home, MOD_MASK_ANY, "\033[1~", 0, +1}, - { XKB_KEY_End, MOD_MASK_CTRL, "\033[J", -1, 0}, - { XKB_KEY_End, MOD_MASK_CTRL, "\033[1;5F", +1, 0}, - { XKB_KEY_End, MOD_MASK_SHIFT, "\033[K", -1, 0}, - { XKB_KEY_End, MOD_MASK_SHIFT, "\033[1;2F", +1, 0}, - { XKB_KEY_End, MOD_MASK_ANY, "\033[4~", 0, 0}, - { XKB_KEY_Prior, MOD_MASK_CTRL, "\033[5;5~", 0, 0}, - { XKB_KEY_Prior, MOD_MASK_SHIFT, "\033[5;2~", 0, 0}, - { XKB_KEY_Next, MOD_MASK_SHIFT, "\033[6;2~", 0, 0}, - { XKB_KEY_Next, MOD_MASK_ANY, "\033[6~", 0, 0}, - { XKB_KEY_F1, MOD_MASK_NONE, "\033OP" , 0, 0}, - { XKB_KEY_F1, /* F13 */ MOD_MASK_SHIFT, "\033[1;2P", 0, 0}, - { XKB_KEY_F1, /* F25 */ MOD_MASK_CTRL, "\033[1;5P", 0, 0}, - { XKB_KEY_F1, /* F37 */ MOD_MASK_LOGO, "\033[1;6P", 0, 0}, - { XKB_KEY_F1, /* F49 */ MOD_MASK_ALT, "\033[1;3P", 0, 0}, - { XKB_KEY_F2, MOD_MASK_NONE, "\033OQ" , 0, 0}, - { XKB_KEY_F2, /* F14 */ MOD_MASK_SHIFT, "\033[1;2Q", 0, 0}, - { XKB_KEY_F2, /* F26 */ MOD_MASK_CTRL, "\033[1;5Q", 0, 0}, - { XKB_KEY_F2, /* F38 */ MOD_MASK_LOGO, "\033[1;6Q", 0, 0}, - { XKB_KEY_F2, /* F50 */ MOD_MASK_ALT, "\033[1;3Q", 0, 0}, - { XKB_KEY_F3, MOD_MASK_NONE, "\033OR" , 0, 0}, - { XKB_KEY_F3, /* F15 */ MOD_MASK_SHIFT, "\033[1;2R", 0, 0}, - { XKB_KEY_F3, /* F27 */ MOD_MASK_CTRL, "\033[1;5R", 0, 0}, - { XKB_KEY_F3, /* F39 */ MOD_MASK_LOGO, "\033[1;6R", 0, 0}, - { XKB_KEY_F3, /* F51 */ MOD_MASK_ALT, "\033[1;3R", 0, 0}, - { XKB_KEY_F4, MOD_MASK_NONE, "\033OS" , 0, 0}, - { XKB_KEY_F4, /* F16 */ MOD_MASK_SHIFT, "\033[1;2S", 0, 0}, - { XKB_KEY_F4, /* F28 */ MOD_MASK_CTRL, "\033[1;5S", 0, 0}, - { XKB_KEY_F4, /* F40 */ MOD_MASK_LOGO, "\033[1;6S", 0, 0}, - { XKB_KEY_F4, /* F52 */ MOD_MASK_ALT, "\033[1;3S", 0, 0}, - { XKB_KEY_F5, MOD_MASK_NONE, "\033[15~", 0, 0}, - { XKB_KEY_F5, /* F17 */ MOD_MASK_SHIFT, "\033[15;2~", 0, 0}, - { XKB_KEY_F5, /* F29 */ MOD_MASK_CTRL, "\033[15;5~", 0, 0}, - { XKB_KEY_F5, /* F41 */ MOD_MASK_LOGO, "\033[15;6~", 0, 0}, - { XKB_KEY_F5, /* F53 */ MOD_MASK_ALT, "\033[15;3~", 0, 0}, - { XKB_KEY_F6, MOD_MASK_NONE, "\033[17~", 0, 0}, - { XKB_KEY_F6, /* F18 */ MOD_MASK_SHIFT, "\033[17;2~", 0, 0}, - { XKB_KEY_F6, /* F30 */ MOD_MASK_CTRL, "\033[17;5~", 0, 0}, - { XKB_KEY_F6, /* F42 */ MOD_MASK_LOGO, "\033[17;6~", 0, 0}, - { XKB_KEY_F6, /* F54 */ MOD_MASK_ALT, "\033[17;3~", 0, 0}, - { XKB_KEY_F7, MOD_MASK_NONE, "\033[18~", 0, 0}, - { XKB_KEY_F7, /* F19 */ MOD_MASK_SHIFT, "\033[18;2~", 0, 0}, - { XKB_KEY_F7, /* F31 */ MOD_MASK_CTRL, "\033[18;5~", 0, 0}, - { XKB_KEY_F7, /* F43 */ MOD_MASK_LOGO, "\033[18;6~", 0, 0}, - { XKB_KEY_F7, /* F55 */ MOD_MASK_ALT, "\033[18;3~", 0, 0}, - { XKB_KEY_F8, MOD_MASK_NONE, "\033[19~", 0, 0}, - { XKB_KEY_F8, /* F20 */ MOD_MASK_SHIFT, "\033[19;2~", 0, 0}, - { XKB_KEY_F8, /* F32 */ MOD_MASK_CTRL, "\033[19;5~", 0, 0}, - { XKB_KEY_F8, /* F44 */ MOD_MASK_LOGO, "\033[19;6~", 0, 0}, - { XKB_KEY_F8, /* F56 */ MOD_MASK_ALT, "\033[19;3~", 0, 0}, - { XKB_KEY_F9, MOD_MASK_NONE, "\033[20~", 0, 0}, - { XKB_KEY_F9, /* F21 */ MOD_MASK_SHIFT, "\033[20;2~", 0, 0}, - { XKB_KEY_F9, /* F33 */ MOD_MASK_CTRL, "\033[20;5~", 0, 0}, - { XKB_KEY_F9, /* F45 */ MOD_MASK_LOGO, "\033[20;6~", 0, 0}, - { XKB_KEY_F9, /* F57 */ MOD_MASK_ALT, "\033[20;3~", 0, 0}, - { XKB_KEY_F10, MOD_MASK_NONE, "\033[21~", 0, 0}, - { XKB_KEY_F10, /* F22 */ MOD_MASK_SHIFT, "\033[21;2~", 0, 0}, - { XKB_KEY_F10, /* F34 */ MOD_MASK_CTRL, "\033[21;5~", 0, 0}, - { XKB_KEY_F10, /* F46 */ MOD_MASK_LOGO, "\033[21;6~", 0, 0}, - { XKB_KEY_F10, /* F58 */ MOD_MASK_ALT, "\033[21;3~", 0, 0}, - { XKB_KEY_F11, MOD_MASK_NONE, "\033[23~", 0, 0}, - { XKB_KEY_F11, /* F23 */ MOD_MASK_SHIFT, "\033[23;2~", 0, 0}, - { XKB_KEY_F11, /* F35 */ MOD_MASK_CTRL, "\033[23;5~", 0, 0}, - { XKB_KEY_F11, /* F47 */ MOD_MASK_LOGO, "\033[23;6~", 0, 0}, - { XKB_KEY_F11, /* F59 */ MOD_MASK_ALT, "\033[23;3~", 0, 0}, - { XKB_KEY_F12, MOD_MASK_NONE, "\033[24~", 0, 0}, - { XKB_KEY_F12, /* F24 */ MOD_MASK_SHIFT, "\033[24;2~", 0, 0}, - { XKB_KEY_F12, /* F36 */ MOD_MASK_CTRL, "\033[24;5~", 0, 0}, - { XKB_KEY_F12, /* F48 */ MOD_MASK_LOGO, "\033[24;6~", 0, 0}, - { XKB_KEY_F12, /* F60 */ MOD_MASK_ALT, "\033[24;3~", 0, 0}, - { XKB_KEY_F13, MOD_MASK_NONE, "\033[1;2P", 0, 0}, - { XKB_KEY_F14, MOD_MASK_NONE, "\033[1;2Q", 0, 0}, - { XKB_KEY_F15, MOD_MASK_NONE, "\033[1;2R", 0, 0}, - { XKB_KEY_F16, MOD_MASK_NONE, "\033[1;2S", 0, 0}, - { XKB_KEY_F17, MOD_MASK_NONE, "\033[15;2~", 0, 0}, - { XKB_KEY_F18, MOD_MASK_NONE, "\033[17;2~", 0, 0}, - { XKB_KEY_F19, MOD_MASK_NONE, "\033[18;2~", 0, 0}, - { XKB_KEY_F20, MOD_MASK_NONE, "\033[19;2~", 0, 0}, - { XKB_KEY_F21, MOD_MASK_NONE, "\033[20;2~", 0, 0}, - { XKB_KEY_F22, MOD_MASK_NONE, "\033[21;2~", 0, 0}, - { XKB_KEY_F23, MOD_MASK_NONE, "\033[23;2~", 0, 0}, - { XKB_KEY_F24, MOD_MASK_NONE, "\033[24;2~", 0, 0}, - { XKB_KEY_F25, MOD_MASK_NONE, "\033[1;5P", 0, 0}, - { XKB_KEY_F26, MOD_MASK_NONE, "\033[1;5Q", 0, 0}, - { XKB_KEY_F27, MOD_MASK_NONE, "\033[1;5R", 0, 0}, - { XKB_KEY_F28, MOD_MASK_NONE, "\033[1;5S", 0, 0}, - { XKB_KEY_F29, MOD_MASK_NONE, "\033[15;5~", 0, 0}, - { XKB_KEY_F30, MOD_MASK_NONE, "\033[17;5~", 0, 0}, - { XKB_KEY_F31, MOD_MASK_NONE, "\033[18;5~", 0, 0}, - { XKB_KEY_F32, MOD_MASK_NONE, "\033[19;5~", 0, 0}, - { XKB_KEY_F33, MOD_MASK_NONE, "\033[20;5~", 0, 0}, - { XKB_KEY_F34, MOD_MASK_NONE, "\033[21;5~", 0, 0}, - { XKB_KEY_F35, MOD_MASK_NONE, "\033[23;5~", 0, 0}, + /* keysym mask string appkey appcursor */ + { XKB_KEY_KP_Home, MOD_MASK_SHIFT, "\033[2J", 0, -1}, + { XKB_KEY_KP_Home, MOD_MASK_SHIFT, "\033[1;2H", 0, +1}, + { XKB_KEY_KP_Home, MOD_MASK_ANY, "\033[H", 0, -1}, + { XKB_KEY_KP_Home, MOD_MASK_ANY, "\033[1~", 0, +1}, + { XKB_KEY_KP_Up, MOD_MASK_ANY, "\033Ox", +1, 0}, + { XKB_KEY_KP_Up, MOD_MASK_ANY, "\033[A", 0, -1}, + { XKB_KEY_KP_Up, MOD_MASK_ANY, "\033OA", 0, +1}, + { XKB_KEY_KP_Down, MOD_MASK_ANY, "\033Or", +1, 0}, + { XKB_KEY_KP_Down, MOD_MASK_ANY, "\033[B", 0, -1}, + { XKB_KEY_KP_Down, MOD_MASK_ANY, "\033OB", 0, +1}, + { XKB_KEY_KP_Left, MOD_MASK_ANY, "\033Ot", +1, 0}, + { XKB_KEY_KP_Left, MOD_MASK_ANY, "\033[D", 0, -1}, + { XKB_KEY_KP_Left, MOD_MASK_ANY, "\033OD", 0, +1}, + { XKB_KEY_KP_Right, MOD_MASK_ANY, "\033Ov", +1, 0}, + { XKB_KEY_KP_Right, MOD_MASK_ANY, "\033[C", 0, -1}, + { XKB_KEY_KP_Right, MOD_MASK_ANY, "\033OC", 0, +1}, + { XKB_KEY_KP_Prior, MOD_MASK_SHIFT, "\033[5;2~", 0, 0}, + { XKB_KEY_KP_Prior, MOD_MASK_ANY, "\033[5~", 0, 0}, + { XKB_KEY_KP_Begin, MOD_MASK_ANY, "\033[E", 0, 0}, + { XKB_KEY_KP_End, MOD_MASK_CTRL, "\033[J", -1, 0}, + { XKB_KEY_KP_End, MOD_MASK_CTRL, "\033[1;5F", +1, 0}, + { XKB_KEY_KP_End, MOD_MASK_SHIFT, "\033[K", -1, 0}, + { XKB_KEY_KP_End, MOD_MASK_SHIFT, "\033[1;2F", +1, 0}, + { XKB_KEY_KP_End, MOD_MASK_ANY, "\033[4~", 0, 0}, + { XKB_KEY_KP_Next, MOD_MASK_SHIFT, "\033[6;2~", 0, 0}, + { XKB_KEY_KP_Next, MOD_MASK_ANY, "\033[6~", 0, 0}, + { XKB_KEY_KP_Insert, MOD_MASK_SHIFT, "\033[2;2~", +1, 0}, + { XKB_KEY_KP_Insert, MOD_MASK_SHIFT, "\033[4l", -1, 0}, + { XKB_KEY_KP_Insert, MOD_MASK_CTRL, "\033[L", -1, 0}, + { XKB_KEY_KP_Insert, MOD_MASK_CTRL, "\033[2;5~", +1, 0}, + { XKB_KEY_KP_Insert, MOD_MASK_ANY, "\033[4h", -1, 0}, + { XKB_KEY_KP_Insert, MOD_MASK_ANY, "\033[2~", +1, 0}, + { XKB_KEY_KP_Delete, MOD_MASK_CTRL, "\033[M", -1, 0}, + { XKB_KEY_KP_Delete, MOD_MASK_CTRL, "\033[3;5~", +1, 0}, + { XKB_KEY_KP_Delete, MOD_MASK_SHIFT, "\033[2K", -1, 0}, + { XKB_KEY_KP_Delete, MOD_MASK_SHIFT, "\033[3;2~", +1, 0}, + { XKB_KEY_KP_Delete, MOD_MASK_ANY, "\033[P", -1, 0}, + { XKB_KEY_KP_Delete, MOD_MASK_ANY, "\033[3~", +1, 0}, + { XKB_KEY_KP_Multiply, MOD_MASK_ANY, "\033Oj", +2, 0}, + { XKB_KEY_KP_Add, MOD_MASK_ANY, "\033Ok", +2, 0}, + { XKB_KEY_KP_Enter, MOD_MASK_ANY, "\033OM", +2, 0}, + { XKB_KEY_KP_Enter, MOD_MASK_ANY, "\r", -1, 0}, + { XKB_KEY_KP_Subtract, MOD_MASK_ANY, "\033Om", +2, 0}, + { XKB_KEY_KP_Decimal, MOD_MASK_ANY, "\033On", +2, 0}, + { XKB_KEY_KP_Divide, MOD_MASK_ANY, "\033Oo", +2, 0}, + { XKB_KEY_KP_0, MOD_MASK_ANY, "\033Op", +2, 0}, + { XKB_KEY_KP_1, MOD_MASK_ANY, "\033Oq", +2, 0}, + { XKB_KEY_KP_2, MOD_MASK_ANY, "\033Or", +2, 0}, + { XKB_KEY_KP_3, MOD_MASK_ANY, "\033Os", +2, 0}, + { XKB_KEY_KP_4, MOD_MASK_ANY, "\033Ot", +2, 0}, + { XKB_KEY_KP_5, MOD_MASK_ANY, "\033Ou", +2, 0}, + { XKB_KEY_KP_6, MOD_MASK_ANY, "\033Ov", +2, 0}, + { XKB_KEY_KP_7, MOD_MASK_ANY, "\033Ow", +2, 0}, + { XKB_KEY_KP_8, MOD_MASK_ANY, "\033Ox", +2, 0}, + { XKB_KEY_KP_9, MOD_MASK_ANY, "\033Oy", +2, 0}, + { XKB_KEY_Up, MOD_MASK_SHIFT, "\033[1;2A", 0, 0}, + { XKB_KEY_Up, MOD_MASK_ALT, "\033[1;3A", 0, 0}, + { XKB_KEY_Up, MOD_MASK_SHIFT|MOD_MASK_ALT, "\033[1;4A", 0, 0}, + { XKB_KEY_Up, MOD_MASK_CTRL, "\033[1;5A", 0, 0}, + { XKB_KEY_Up, MOD_MASK_SHIFT|MOD_MASK_CTRL,"\033[1;6A", 0, 0}, + { XKB_KEY_Up, MOD_MASK_CTRL|MOD_MASK_ALT, "\033[1;7A", 0, 0}, + { XKB_KEY_Up, MOD_MASK_SHIFT|MOD_MASK_CTRL|MOD_MASK_ALT,"\033[1;8A", 0, 0}, + { XKB_KEY_Up, MOD_MASK_ANY, "\033[A", 0, -1}, + { XKB_KEY_Up, MOD_MASK_ANY, "\033OA", 0, +1}, + { XKB_KEY_Down, MOD_MASK_SHIFT, "\033[1;2B", 0, 0}, + { XKB_KEY_Down, MOD_MASK_ALT, "\033[1;3B", 0, 0}, + { XKB_KEY_Down, MOD_MASK_SHIFT|MOD_MASK_ALT,"\033[1;4B", 0, 0}, + { XKB_KEY_Down, MOD_MASK_CTRL, "\033[1;5B", 0, 0}, + { XKB_KEY_Down, MOD_MASK_SHIFT|MOD_MASK_CTRL,"\033[1;6B", 0, 0}, + { XKB_KEY_Down, MOD_MASK_CTRL|MOD_MASK_ALT,"\033[1;7B", 0, 0}, + { XKB_KEY_Down, MOD_MASK_SHIFT|MOD_MASK_CTRL|MOD_MASK_ALT,"\033[1;8B",0,0}, + { XKB_KEY_Down, MOD_MASK_ANY, "\033[B", 0, -1}, + { XKB_KEY_Down, MOD_MASK_ANY, "\033OB", 0, +1}, + { XKB_KEY_Left, MOD_MASK_SHIFT, "\033[1;2D", 0, 0}, + { XKB_KEY_Left, MOD_MASK_ALT, "\033[1;3D", 0, 0}, + { XKB_KEY_Left, MOD_MASK_SHIFT|MOD_MASK_ALT,"\033[1;4D", 0, 0}, + { XKB_KEY_Left, MOD_MASK_CTRL, "\033[1;5D", 0, 0}, + { XKB_KEY_Left, MOD_MASK_SHIFT|MOD_MASK_CTRL,"\033[1;6D", 0, 0}, + { XKB_KEY_Left, MOD_MASK_CTRL|MOD_MASK_ALT,"\033[1;7D", 0, 0}, + { XKB_KEY_Left, MOD_MASK_SHIFT|MOD_MASK_CTRL|MOD_MASK_ALT,"\033[1;8D",0,0}, + { XKB_KEY_Left, MOD_MASK_ANY, "\033[D", 0, -1}, + { XKB_KEY_Left, MOD_MASK_ANY, "\033OD", 0, +1}, + { XKB_KEY_Right, MOD_MASK_SHIFT, "\033[1;2C", 0, 0}, + { XKB_KEY_Right, MOD_MASK_ALT, "\033[1;3C", 0, 0}, + { XKB_KEY_Right,MOD_MASK_SHIFT|MOD_MASK_ALT,"\033[1;4C", 0, 0}, + { XKB_KEY_Right, MOD_MASK_CTRL, "\033[1;5C", 0, 0}, + { XKB_KEY_Right,MOD_MASK_SHIFT|MOD_MASK_CTRL,"\033[1;6C", 0, 0}, + { XKB_KEY_Right,MOD_MASK_CTRL|MOD_MASK_ALT,"\033[1;7C", 0, 0}, + { XKB_KEY_Right,MOD_MASK_SHIFT|MOD_MASK_CTRL|MOD_MASK_ALT,"\033[1;8C",0,0}, + { XKB_KEY_Right, MOD_MASK_ANY, "\033[C", 0, -1}, + { XKB_KEY_Right, MOD_MASK_ANY, "\033OC", 0, +1}, + { XKB_KEY_ISO_Left_Tab, MOD_MASK_SHIFT, "\033[Z", 0, 0}, + { XKB_KEY_Return, MOD_MASK_ALT, "\033\r", 0, 0}, + { XKB_KEY_Return, MOD_MASK_ANY, "\r", 0, 0}, + { XKB_KEY_Insert, MOD_MASK_SHIFT, "\033[4l", -1, 0}, + { XKB_KEY_Insert, MOD_MASK_SHIFT, "\033[2;2~", +1, 0}, + { XKB_KEY_Insert, MOD_MASK_CTRL, "\033[L", -1, 0}, + { XKB_KEY_Insert, MOD_MASK_CTRL, "\033[2;5~", +1, 0}, + { XKB_KEY_Insert, MOD_MASK_ANY, "\033[4h", -1, 0}, + { XKB_KEY_Insert, MOD_MASK_ANY, "\033[2~", +1, 0}, + { XKB_KEY_Delete, MOD_MASK_CTRL, "\033[M", -1, 0}, + { XKB_KEY_Delete, MOD_MASK_CTRL, "\033[3;5~", +1, 0}, + { XKB_KEY_Delete, MOD_MASK_SHIFT, "\033[2K", -1, 0}, + { XKB_KEY_Delete, MOD_MASK_SHIFT, "\033[3;2~", +1, 0}, + { XKB_KEY_Delete, MOD_MASK_ANY, "\033[P", -1, 0}, + { XKB_KEY_Delete, MOD_MASK_ANY, "\033[3~", +1, 0}, + { XKB_KEY_BackSpace, MOD_MASK_NONE, "\177", 0, 0}, + { XKB_KEY_BackSpace, MOD_MASK_ALT, "\033\177", 0, 0}, + { XKB_KEY_Home, MOD_MASK_SHIFT, "\033[2J", 0, -1}, + { XKB_KEY_Home, MOD_MASK_SHIFT, "\033[1;2H", 0, +1}, + { XKB_KEY_Home, MOD_MASK_ANY, "\033[H", 0, -1}, + { XKB_KEY_Home, MOD_MASK_ANY, "\033[1~", 0, +1}, + { XKB_KEY_End, MOD_MASK_CTRL, "\033[J", -1, 0}, + { XKB_KEY_End, MOD_MASK_CTRL, "\033[1;5F", +1, 0}, + { XKB_KEY_End, MOD_MASK_SHIFT, "\033[K", -1, 0}, + { XKB_KEY_End, MOD_MASK_SHIFT, "\033[1;2F", +1, 0}, + { XKB_KEY_End, MOD_MASK_ANY, "\033[4~", 0, 0}, + { XKB_KEY_Prior, MOD_MASK_CTRL, "\033[5;5~", 0, 0}, + { XKB_KEY_Prior, MOD_MASK_SHIFT, "\033[5;2~", 0, 0}, + { XKB_KEY_Prior, MOD_MASK_ANY, "\033[5~", 0, 0}, + { XKB_KEY_Next, MOD_MASK_CTRL, "\033[6;5~", 0, 0}, + { XKB_KEY_Next, MOD_MASK_SHIFT, "\033[6;2~", 0, 0}, + { XKB_KEY_Next, MOD_MASK_ANY, "\033[6~", 0, 0}, + { XKB_KEY_F1, MOD_MASK_NONE, "\033OP" , 0, 0}, + { XKB_KEY_F1, /* F13 */ MOD_MASK_SHIFT, "\033[1;2P", 0, 0}, + { XKB_KEY_F1, /* F25 */ MOD_MASK_CTRL, "\033[1;5P", 0, 0}, + { XKB_KEY_F1, /* F37 */ MOD_MASK_LOGO, "\033[1;6P", 0, 0}, + { XKB_KEY_F1, /* F49 */ MOD_MASK_ALT, "\033[1;3P", 0, 0}, + { XKB_KEY_F2, MOD_MASK_NONE, "\033OQ" , 0, 0}, + { XKB_KEY_F2, /* F14 */ MOD_MASK_SHIFT, "\033[1;2Q", 0, 0}, + { XKB_KEY_F2, /* F26 */ MOD_MASK_CTRL, "\033[1;5Q", 0, 0}, + { XKB_KEY_F2, /* F38 */ MOD_MASK_LOGO, "\033[1;6Q", 0, 0}, + { XKB_KEY_F2, /* F50 */ MOD_MASK_ALT, "\033[1;3Q", 0, 0}, + { XKB_KEY_F3, MOD_MASK_NONE, "\033OR" , 0, 0}, + { XKB_KEY_F3, /* F15 */ MOD_MASK_SHIFT, "\033[1;2R", 0, 0}, + { XKB_KEY_F3, /* F27 */ MOD_MASK_CTRL, "\033[1;5R", 0, 0}, + { XKB_KEY_F3, /* F39 */ MOD_MASK_LOGO, "\033[1;6R", 0, 0}, + { XKB_KEY_F3, /* F51 */ MOD_MASK_ALT, "\033[1;3R", 0, 0}, + { XKB_KEY_F4, MOD_MASK_NONE, "\033OS" , 0, 0}, + { XKB_KEY_F4, /* F16 */ MOD_MASK_SHIFT, "\033[1;2S", 0, 0}, + { XKB_KEY_F4, /* F28 */ MOD_MASK_CTRL, "\033[1;5S", 0, 0}, + { XKB_KEY_F4, /* F40 */ MOD_MASK_LOGO, "\033[1;6S", 0, 0}, + { XKB_KEY_F4, /* F52 */ MOD_MASK_ALT, "\033[1;3S", 0, 0}, + { XKB_KEY_F5, MOD_MASK_NONE, "\033[15~", 0, 0}, + { XKB_KEY_F5, /* F17 */ MOD_MASK_SHIFT, "\033[15;2~", 0, 0}, + { XKB_KEY_F5, /* F29 */ MOD_MASK_CTRL, "\033[15;5~", 0, 0}, + { XKB_KEY_F5, /* F41 */ MOD_MASK_LOGO, "\033[15;6~", 0, 0}, + { XKB_KEY_F5, /* F53 */ MOD_MASK_ALT, "\033[15;3~", 0, 0}, + { XKB_KEY_F6, MOD_MASK_NONE, "\033[17~", 0, 0}, + { XKB_KEY_F6, /* F18 */ MOD_MASK_SHIFT, "\033[17;2~", 0, 0}, + { XKB_KEY_F6, /* F30 */ MOD_MASK_CTRL, "\033[17;5~", 0, 0}, + { XKB_KEY_F6, /* F42 */ MOD_MASK_LOGO, "\033[17;6~", 0, 0}, + { XKB_KEY_F6, /* F54 */ MOD_MASK_ALT, "\033[17;3~", 0, 0}, + { XKB_KEY_F7, MOD_MASK_NONE, "\033[18~", 0, 0}, + { XKB_KEY_F7, /* F19 */ MOD_MASK_SHIFT, "\033[18;2~", 0, 0}, + { XKB_KEY_F7, /* F31 */ MOD_MASK_CTRL, "\033[18;5~", 0, 0}, + { XKB_KEY_F7, /* F43 */ MOD_MASK_LOGO, "\033[18;6~", 0, 0}, + { XKB_KEY_F7, /* F55 */ MOD_MASK_ALT, "\033[18;3~", 0, 0}, + { XKB_KEY_F8, MOD_MASK_NONE, "\033[19~", 0, 0}, + { XKB_KEY_F8, /* F20 */ MOD_MASK_SHIFT, "\033[19;2~", 0, 0}, + { XKB_KEY_F8, /* F32 */ MOD_MASK_CTRL, "\033[19;5~", 0, 0}, + { XKB_KEY_F8, /* F44 */ MOD_MASK_LOGO, "\033[19;6~", 0, 0}, + { XKB_KEY_F8, /* F56 */ MOD_MASK_ALT, "\033[19;3~", 0, 0}, + { XKB_KEY_F9, MOD_MASK_NONE, "\033[20~", 0, 0}, + { XKB_KEY_F9, /* F21 */ MOD_MASK_SHIFT, "\033[20;2~", 0, 0}, + { XKB_KEY_F9, /* F33 */ MOD_MASK_CTRL, "\033[20;5~", 0, 0}, + { XKB_KEY_F9, /* F45 */ MOD_MASK_LOGO, "\033[20;6~", 0, 0}, + { XKB_KEY_F9, /* F57 */ MOD_MASK_ALT, "\033[20;3~", 0, 0}, + { XKB_KEY_F10, MOD_MASK_NONE, "\033[21~", 0, 0}, + { XKB_KEY_F10, /* F22 */ MOD_MASK_SHIFT, "\033[21;2~", 0, 0}, + { XKB_KEY_F10, /* F34 */ MOD_MASK_CTRL, "\033[21;5~", 0, 0}, + { XKB_KEY_F10, /* F46 */ MOD_MASK_LOGO, "\033[21;6~", 0, 0}, + { XKB_KEY_F10, /* F58 */ MOD_MASK_ALT, "\033[21;3~", 0, 0}, + { XKB_KEY_F11, MOD_MASK_NONE, "\033[23~", 0, 0}, + { XKB_KEY_F11, /* F23 */ MOD_MASK_SHIFT, "\033[23;2~", 0, 0}, + { XKB_KEY_F11, /* F35 */ MOD_MASK_CTRL, "\033[23;5~", 0, 0}, + { XKB_KEY_F11, /* F47 */ MOD_MASK_LOGO, "\033[23;6~", 0, 0}, + { XKB_KEY_F11, /* F59 */ MOD_MASK_ALT, "\033[23;3~", 0, 0}, + { XKB_KEY_F12, MOD_MASK_NONE, "\033[24~", 0, 0}, + { XKB_KEY_F12, /* F24 */ MOD_MASK_SHIFT, "\033[24;2~", 0, 0}, + { XKB_KEY_F12, /* F36 */ MOD_MASK_CTRL, "\033[24;5~", 0, 0}, + { XKB_KEY_F12, /* F48 */ MOD_MASK_LOGO, "\033[24;6~", 0, 0}, + { XKB_KEY_F12, /* F60 */ MOD_MASK_ALT, "\033[24;3~", 0, 0}, + { XKB_KEY_F13, MOD_MASK_NONE, "\033[1;2P", 0, 0}, + { XKB_KEY_F14, MOD_MASK_NONE, "\033[1;2Q", 0, 0}, + { XKB_KEY_F15, MOD_MASK_NONE, "\033[1;2R", 0, 0}, + { XKB_KEY_F16, MOD_MASK_NONE, "\033[1;2S", 0, 0}, + { XKB_KEY_F17, MOD_MASK_NONE, "\033[15;2~", 0, 0}, + { XKB_KEY_F18, MOD_MASK_NONE, "\033[17;2~", 0, 0}, + { XKB_KEY_F19, MOD_MASK_NONE, "\033[18;2~", 0, 0}, + { XKB_KEY_F20, MOD_MASK_NONE, "\033[19;2~", 0, 0}, + { XKB_KEY_F21, MOD_MASK_NONE, "\033[20;2~", 0, 0}, + { XKB_KEY_F22, MOD_MASK_NONE, "\033[21;2~", 0, 0}, + { XKB_KEY_F23, MOD_MASK_NONE, "\033[23;2~", 0, 0}, + { XKB_KEY_F24, MOD_MASK_NONE, "\033[24;2~", 0, 0}, + { XKB_KEY_F25, MOD_MASK_NONE, "\033[1;5P", 0, 0}, + { XKB_KEY_F26, MOD_MASK_NONE, "\033[1;5Q", 0, 0}, + { XKB_KEY_F27, MOD_MASK_NONE, "\033[1;5R", 0, 0}, + { XKB_KEY_F28, MOD_MASK_NONE, "\033[1;5S", 0, 0}, + { XKB_KEY_F29, MOD_MASK_NONE, "\033[15;5~", 0, 0}, + { XKB_KEY_F30, MOD_MASK_NONE, "\033[17;5~", 0, 0}, + { XKB_KEY_F31, MOD_MASK_NONE, "\033[18;5~", 0, 0}, + { XKB_KEY_F32, MOD_MASK_NONE, "\033[19;5~", 0, 0}, + { XKB_KEY_F33, MOD_MASK_NONE, "\033[20;5~", 0, 0}, + { XKB_KEY_F34, MOD_MASK_NONE, "\033[21;5~", 0, 0}, + { XKB_KEY_F35, MOD_MASK_NONE, "\033[23;5~", 0, 0}, }; /* @@ -448,7 +449,7 @@ static Key key[] = { * If no match is found, regular selection is used. */ static uint selmasks[] = { - [SEL_RECTANGULAR] = MOD_MASK_ALT, + [SEL_RECTANGULAR] = MOD_MASK_ALT, }; /* @@ -456,6 +457,6 @@ static uint selmasks[] = { * of single wide characters. */ static char ascii_printable[] = - " !\"#$%&'()*+,-./0123456789:;<=>?" - "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_" - "`abcdefghijklmnopqrstuvwxyz{|}~"; + " !\"#$%&'()*+,-./0123456789:;<=>?" + "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_" + "`abcdefghijklmnopqrstuvwxyz{|}~"; diff --git a/st.c b/st.c index 542dc53..0edbb67 100644 --- a/st.c +++ b/st.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include @@ -35,14 +36,10 @@ /* macros */ #define IS_SET(flag) ((term.mode & (flag)) != 0) -#define NUMMAXLEN(x) ((int)(sizeof(x) * 2.56 + 0.5) + 1) #define ISCONTROLC0(c) (BETWEEN(c, 0, 0x1f) || (c) == '\177') #define ISCONTROLC1(c) (BETWEEN(c, 0x80, 0x9f)) #define ISCONTROL(c) (ISCONTROLC0(c) || ISCONTROLC1(c)) -#define ISDELIM(u) (utf8strchr(worddelimiters, u) != NULL) - -/* constants */ -#define ISO14755CMD "dmenu -w \"$WINDOWID\" -p codepoint: 2) { - char *dec; - dec = base64dec(strescseq.args[2]); if (dec) { xsetsel(dec); @@ -1875,7 +1864,10 @@ strhandle(void) case 104: /* color reset, here p = NULL */ j = (narg > 1) ? atoi(strescseq.args[1]) : -1; if (xsetcolorname(j, p)) { - fprintf(stderr, "erresc: invalid color %s\n", p); + if (par == 104 && narg <= 1) + return; /* color reset without parameter */ + fprintf(stderr, "erresc: invalid color j=%d, p=%s\n", + j, p ? p : "(null)"); } else { /* * TODO if defaultbg color is changed, borders @@ -1972,28 +1964,6 @@ tprinter(char *s, size_t len) } } -void -iso14755(const Arg *arg) -{ - FILE *p; - char *us, *e, codepoint[9], uc[UTF_SIZ]; - unsigned long utf32; - - if (!(p = popen(ISO14755CMD, "r"))) - return; - - us = fgets(codepoint, sizeof(codepoint), p); - pclose(p); - - if (!us || *us == '\0' || *us == '-' || strlen(us) > 7) - return; - if ((utf32 = strtoul(us, &e, 16)) == ULONG_MAX || - (*e != '\n' && *e != '\0')) - return; - - ttywrite(uc, utf8encode(utf32, uc), 1); -} - void toggleprinter(const Arg *arg) { @@ -2278,7 +2248,7 @@ eschandle(uchar ascii) case 'Z': /* DECID -- Identify Terminal */ ttywrite(vtiden, strlen(vtiden), 0); break; - case 'c': /* RIS -- Reset to inital state */ + case 'c': /* RIS -- Reset to initial state */ treset(); resettitle(); xloadcols(); @@ -2349,7 +2319,6 @@ tputc(Rune u) goto check_control_code; } - if (IS_SET(MODE_SIXEL)) { /* TODO: implement sixel mode */ return; diff --git a/st.h b/st.h index 371df19..38b5980 100644 --- a/st.h +++ b/st.h @@ -83,7 +83,6 @@ 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 *); @@ -119,7 +118,7 @@ char *xstrdup(char *); extern char *utmp; extern char *stty_args; extern char *vtiden; -extern char *worddelimiters; +extern wchar_t *worddelimiters; extern int allowaltscreen; extern char *termname; extern unsigned int tabspaces; diff --git a/win.h b/win.h index 0358977..877048c 100644 --- a/win.h +++ b/win.h @@ -36,5 +36,4 @@ void xsetmode(int, unsigned int); void xsetpointermotion(int); void xsetsel(char *); int xstartdraw(void); - void wlneeddraw(void); diff --git a/wl.c b/wl.c index c49a931..70beddb 100644 --- a/wl.c +++ b/wl.c @@ -1,5 +1,6 @@ /* See LICENSE for license details. */ #include +#include #include #include #include @@ -304,8 +305,9 @@ typedef struct { } Fontcache; /* Fontcache is an array now. A new font will be appended to the array. */ -static Fontcache frc[16]; +static Fontcache *frc = NULL; static int frclen = 0; +static int frccap = 0; static char *usedfont = NULL; static double usedfontsize = 0; static double defaultfontsize = 0; @@ -429,6 +431,8 @@ cresize(int width, int height) col = (win.w - 2 * borderpx) / win.cw; row = (win.h - 2 * borderpx) / win.ch; + col = MAX(1, col); + row = MAX(1, row); tresize(col, row); wlresize(col, row); @@ -706,6 +710,9 @@ ptraxis(void * data, struct wl_pointer * pointer, uint32_t time, uint32_t axis, void setsel(char *str, uint32_t serial) { + if (!str) + return; + free(wlsel.primary); wlsel.primary = str; @@ -941,8 +948,8 @@ wlresize(int col, int row) { union wld_object object; - win.tw = MAX(1, col * win.cw); - win.th = MAX(1, row * win.ch); + win.tw = col * win.cw; + win.th = row * win.ch; wld.oldbuffer = wld.buffer; wld.buffer = wld_create_buffer(wld.ctx, win.w, win.h, @@ -954,7 +961,7 @@ wlresize(int col, int row) void xsettitle(char *title) { - DEFAULT(title, "st-wl"); + DEFAULT(title, opt_title); xdg_toplevel_set_title(wl.xdgtoplevel, title); } @@ -1045,9 +1052,12 @@ void xloadcols(void) { int i; + static int loaded; - dc.collen = MAX(LEN(colorname), 256); - dc.col = xmalloc(dc.collen * sizeof(uint32_t)); + if(!loaded) { + dc.collen = MAX(LEN(colorname), 256); + dc.col = xmalloc(dc.collen * sizeof(uint32_t)); + } for (i = 0; i < dc.collen; i++) if (!wlloadcolor(i, NULL, &dc.col[i])) { @@ -1056,6 +1066,8 @@ xloadcols(void) else die("Could not allocate color %d\n", i); } + + loaded = 1; } int @@ -1117,7 +1129,7 @@ wlloadfont(Font *f, FcPattern *pattern) if ((FcPatternGetInteger(match, "slant", 0, &haveattr) != FcResultMatch) || haveattr < wantattr) { f->badslant = 1; - fputs("st-wl: font slant does not match\n", stderr); + fputs("font slant does not match\n", stderr); } } @@ -1126,7 +1138,7 @@ wlloadfont(Font *f, FcPattern *pattern) if ((FcPatternGetInteger(match, "weight", 0, &haveattr) != FcResultMatch) || haveattr != wantattr) { f->badweight = 1; - fputs("st-wl: font weight does not match\n", stderr); + fputs("font weight does not match\n", stderr); } } @@ -1152,7 +1164,6 @@ wlloadfonts(char *fontstr, double fontsize) { FcPattern *pattern; double fontval; - float ceilf(float); if (fontstr[0] == '-') { /* XXX: need XftXlfdParse equivalent */ @@ -1162,7 +1173,7 @@ wlloadfonts(char *fontstr, double fontsize) } if (!pattern) - die("st-wl: can't open font %s\n", fontstr); + die("can't open font %s\n", fontstr); if (fontsize > 1) { FcPatternDel(pattern, FC_PIXEL_SIZE); @@ -1191,7 +1202,7 @@ wlloadfonts(char *fontstr, double fontsize) FcDefaultSubstitute(pattern); if (wlloadfont(&dc.font, pattern)) - die("st-wl: can't open font %s\n", fontstr); + die("can't open font %s\n", fontstr); if (usedfontsize < 0) { FcPatternGetDouble(dc.font.pattern, @@ -1208,17 +1219,17 @@ wlloadfonts(char *fontstr, double fontsize) FcPatternDel(pattern, FC_SLANT); FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ITALIC); if (wlloadfont(&dc.ifont, pattern)) - die("st-wl: can't open font %s\n", fontstr); + die("can't open font %s\n", fontstr); FcPatternDel(pattern, FC_WEIGHT); FcPatternAddInteger(pattern, FC_WEIGHT, FC_WEIGHT_BOLD); if (wlloadfont(&dc.ibfont, pattern)) - die("st-wl: can't open font %s\n", fontstr); + die("can't open font %s\n", fontstr); FcPatternDel(pattern, FC_SLANT); FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ROMAN); if (wlloadfont(&dc.bfont, pattern)) - die("st-wl: can't open font %s\n", fontstr); + die("can't open font %s\n", fontstr); FcPatternDestroy(pattern); } @@ -1527,10 +1538,12 @@ wldraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) /* * Overwrite or create the new cache entry. */ - if (frclen >= LEN(frc)) { - frclen = LEN(frc) - 1; - wld_font_close(frc[frclen].font); - frc[frclen].unicodep = 0; + if (frclen >= frccap) { + frccap += 16; + frc = xrealloc(frc, frccap * sizeof(Fontcache)); + // frclen = LEN(frc) - 1; + // wld_font_close(frc[frclen].font); + // frc[frclen].unicodep = 0; } frc[frclen].font = wld_font_open_pattern(wld.fontctx, @@ -1990,19 +2003,19 @@ main(int argc, char *argv[]) opt_embed = EARGF(usage()); break; case 'v': - die("%s " VERSION " (c) 2010-2016 st-wl engineers\n", argv0); + die("%s " VERSION "\n", argv0); break; default: usage(); } ARGEND; run: - if (argc > 0) { - /* eat all remaining arguments */ + if (argc > 0) /* eat all remaining arguments */ opt_cmd = argv; - if (!opt_title && !opt_line) - opt_title = basename(xstrdup(argv[0])); - } + + if (!opt_title) + opt_title = (opt_line || !opt_cmd) ? "st" : opt_cmd[0]; + setlocale(LC_CTYPE, ""); cols = MAX(cols, 1); rows = MAX(rows, 1); From f43d695d5004ca1cc86d5f5dc44065373abe2018 Mon Sep 17 00:00:00 2001 From: ian <42294085+ianbeyst@users.noreply.github.com> Date: Sat, 15 Jun 2019 17:39:15 +0200 Subject: [PATCH 127/129] Fixed window visibility handling, fixed makefile install bug, other bugfixes There was an issue where the surface never gets drawn if xstartdraw returns the window visibility mode that was temporarily fixed by always returning 1. This has been fixed by simply initializing win.mode to MODE_VISIBLE. Also removed the useless wl.vis attribute. --- Makefile | 6 +++--- wl.c | 20 ++++++++++---------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/Makefile b/Makefile index 8ac213b..7eb5c77 100644 --- a/Makefile +++ b/Makefile @@ -29,8 +29,8 @@ xdg-shell-client-protocol.h: .c.o: $(CC) $(STCFLAGS) -c $< -st.o: config.h st.h win.h -wl.o: arg.h config.h st.h win.h xdg-shell-client-protocol.h +st.o: st.h win.h +wl.o: arg.h st.h win.h config.h xdg-shell-client-protocol.h $(OBJ): config.h config.mk @@ -48,7 +48,7 @@ dist: clean tar -cf - st-wl-$(VERSION) | gzip > st-wl-$(VERSION).tar.gz rm -rf st-wl-$(VERSION) -install: st +install: st-wl mkdir -p $(DESTDIR)$(PREFIX)/bin cp -f st-wl $(DESTDIR)$(PREFIX)/bin chmod 755 $(DESTDIR)$(PREFIX)/bin/st-wl diff --git a/wl.c b/wl.c index 70beddb..552bf33 100644 --- a/wl.c +++ b/wl.c @@ -122,7 +122,6 @@ typedef struct { XKB xkb; bool configured; int px, py; /* pointer x and y */ - int vis; struct wl_callback * framecb; uint32_t globalserial; /* global event serial */ bool needdraw; @@ -968,7 +967,6 @@ xsettitle(char *title) void surfenter(void *data, struct wl_surface *surface, struct wl_output *output) { - wl.vis++; if (!(IS_SET(MODE_VISIBLE))) win.mode |= MODE_VISIBLE; } @@ -976,7 +974,7 @@ surfenter(void *data, struct wl_surface *surface, struct wl_output *output) void surfleave(void *data, struct wl_surface *surface, struct wl_output *output) { - if (--wl.vis == 0) + if(IS_SET(MODE_VISIBLE)) win.mode &= ~MODE_VISIBLE; } @@ -1002,6 +1000,7 @@ xdgtoplevelconfigure(void *data, struct xdg_toplevel *toplevel, { if (w == win.w && h == win.h) return; + cresize(w, h); if (!wl.configured) wl.configured = true; @@ -1265,10 +1264,9 @@ wlneeddraw(void) int xstartdraw(void) { - wld_set_target_buffer(wld.renderer, wld.buffer); - - return 1; // Should be IS_SET(MODE_VISIBLE), but this results in no window. - // TODO: Implement proper MODE_VISIBLE handling. + if(IS_SET(MODE_VISIBLE)) + wld_set_target_buffer(wld.renderer, wld.buffer); + return IS_SET(MODE_VISIBLE); } void @@ -1839,7 +1837,6 @@ wlinit(int cols, int rows) xloadcols(); wlloadcursor(); - wl.vis = 0; win.h = 2 * borderpx + rows * win.ch; win.w = 2 * borderpx + cols * win.cw; @@ -1878,6 +1875,10 @@ run(void) wl_display_roundtrip(wl.dpy); ttyfd = ttynew(opt_line, shell, opt_io, opt_cmd); cresize(win.w, win.h); + + if (!(IS_SET(MODE_VISIBLE))) + win.mode |= MODE_VISIBLE; + draw(); clock_gettime(CLOCK_MONOTONIC, &last); @@ -2014,7 +2015,7 @@ main(int argc, char *argv[]) opt_cmd = argv; if (!opt_title) - opt_title = (opt_line || !opt_cmd) ? "st" : opt_cmd[0]; + opt_title = (opt_line || !opt_cmd) ? "st-wl" : opt_cmd[0]; setlocale(LC_CTYPE, ""); cols = MAX(cols, 1); @@ -2026,4 +2027,3 @@ main(int argc, char *argv[]) return 0; } - From cfde55e22bab00ea6f2c818d8a6de6137d8262f9 Mon Sep 17 00:00:00 2001 From: ian <42294085+ianbeyst@users.noreply.github.com> Date: Sat, 15 Jun 2019 18:37:37 +0200 Subject: [PATCH 128/129] removed x.c --- x.c | 1986 ----------------------------------------------------------- 1 file changed, 1986 deletions(-) delete mode 100644 x.c diff --git a/x.c b/x.c deleted file mode 100644 index 5828a3b..0000000 --- a/x.c +++ /dev/null @@ -1,1986 +0,0 @@ -/* See LICENSE for license details. */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -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 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 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 ximopen(Display *); -static void ximinstantiate(Display *, XPointer, XPointer); -static void ximdestroy(XIM, XPointer, XPointer); -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 = NULL; -static int frclen = 0; -static int frccap = 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; - 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; - } - } - - 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(); -} - -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; - col = MAX(1, col); - row = MAX(1, row); - - tresize(col, row); - xresize(col, row); - ttyresize(win.tw, win.th); -} - -void -xresize(int col, int row) -{ - win.tw = col * win.cw; - win.th = row * win.ch; - - XFreePixmap(xw.dpy, xw.buf); - xw.buf = XCreatePixmap(xw.dpy, xw.win, win.w, win.h, - DefaultDepth(xw.dpy, xw.scr)); - XftDrawChange(xw.draw, xw.buf); - xclear(0, 0, win.w, win.h); - - /* resize to new width */ - 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; - - if (loaded) { - for (cp = dc.col; cp < &dc.col[dc.collen]; ++cp) - XftColorFree(xw.dpy, xw.vis, xw.cmap, cp); - } else { - dc.collen = MAX(LEN(colorname), 256); - dc.col = xmalloc(dc.collen * sizeof(Color)); - } - - 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); - } - 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; -} - -/* - * 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 | PMinSize; - 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; - sizeh->min_height = win.ch + 2 * borderpx; - sizeh->min_width = win.cw + 2 * borderpx; - if (xw.isfixed) { - sizeh->flags |= PMaxSize; - 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("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("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("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("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); - - FcPatternDel(pattern, FC_SLANT); - FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ITALIC); - if (xloadfont(&dc.ifont, pattern)) - die("can't open font %s\n", fontstr); - - FcPatternDel(pattern, FC_WEIGHT); - FcPatternAddInteger(pattern, FC_WEIGHT, FC_WEIGHT_BOLD); - if (xloadfont(&dc.ibfont, pattern)) - die("can't open font %s\n", fontstr); - - FcPatternDel(pattern, FC_SLANT); - FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ROMAN); - if (xloadfont(&dc.bfont, pattern)) - die("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 -ximopen(Display *dpy) -{ - XIMCallback destroy = { .client_data = NULL, .callback = ximdestroy }; - - if ((xw.xim = XOpenIM(xw.dpy, NULL, NULL, NULL)) == NULL) { - XSetLocaleModifiers("@im=local"); - if ((xw.xim = XOpenIM(xw.dpy, NULL, NULL, NULL)) == NULL) { - XSetLocaleModifiers("@im="); - if ((xw.xim = XOpenIM(xw.dpy, NULL, NULL, NULL)) == NULL) - die("XOpenIM failed. Could not open input device.\n"); - } - } - if (XSetIMValues(xw.xim, XNDestroyCallback, &destroy, NULL) != NULL) - die("XSetIMValues failed. Could not set input method value.\n"); - xw.xic = XCreateIC(xw.xim, XNInputStyle, XIMPreeditNothing | XIMStatusNothing, - XNClientWindow, xw.win, XNFocusWindow, xw.win, NULL); - if (xw.xic == NULL) - die("XCreateIC failed. Could not obtain input method.\n"); -} - -void -ximinstantiate(Display *dpy, XPointer client, XPointer call) -{ - ximopen(dpy); - XUnregisterIMInstantiateCallback(xw.dpy, NULL, NULL, NULL, - ximinstantiate, NULL); -} - -void -ximdestroy(XIM xim, XPointer client, XPointer call) -{ - xw.xim = NULL; - XRegisterIMInstantiateCallback(xw.dpy, NULL, NULL, NULL, - ximinstantiate, NULL); -} - -void -xinit(int cols, int rows) -{ - XGCValues gcvalues; - 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.vis = XDefaultVisual(xw.dpy, xw.scr); - - /* font */ - if (!FcInit()) - die("could not init fontconfig.\n"); - - usedfont = (opt_font == NULL)? font : opt_font; - xloadfonts(usedfont, 0); - - /* colors */ - xw.cmap = XDefaultColormap(xw.dpy, xw.scr); - 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 | KeyReleaseMask - | 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, XDefaultDepth(xw.dpy, xw.scr), 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)); - 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 */ - ximopen(xw.dpy); - - /* 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; 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; - } - - /* 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); - - /* Allocate memory for the new cache entry. */ - if (frclen >= frccap) { - frccap += 16; - frc = xrealloc(frc, frccap * sizeof(Fontcache)); - } - - frc[frclen].font = XftFontOpenPattern(xw.dpy, - fontpattern); - if (!frc[frclen].font) - die("XftFontOpenPattern failed seeking fallback font: %s\n", - strerror(errno)); - frc[frclen].flags = frcflags; - frc[frclen].unicodep = rune; - - glyphidx = XftCharIndex(xw.dpy, frc[frclen].font, rune); - - f = frclen; - frclen++; - - FcPatternDestroy(fcpattern); - FcCharSetDestroy(fccharset); - } - - specs[numspecs].font = frc[f].font; - specs[numspecs].glyph = glyphidx; - specs[numspecs].x = (short)xp; - specs[numspecs].y = (short)yp; - xp += runewidth; - numspecs++; - } - - 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 + 8]; - - 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 + dc.font.ascent + 1, - width, 1); - } - - if (base.mode & ATTR_STRUCK) { - XftDrawRect(xw.draw, fg, winx, winy + 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 -xximspot(int x, int y) -{ - XPoint spot = { borderpx + x * win.cw, borderpx + (y + 1) * win.ch }; - XVaNestedList attr = XVaCreateNestedList(0, XNSpotLocation, &spot, NULL); - - XSetICValues(xw.xic, XNPreeditAttributes, attr, NULL); - XFree(attr); -} - -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 "\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; -} From a0629747acc7c57cc827c539659c28084402f3a5 Mon Sep 17 00:00:00 2001 From: ian <42294085+ianbeyst@users.noreply.github.com> Date: Mon, 17 Jun 2019 22:46:36 +0200 Subject: [PATCH 129/129] cleanup, reordered some code --- st.c | 4 +- wl.c | 316 +++++++++++++++++++++++++++++------------------------------ 2 files changed, 158 insertions(+), 162 deletions(-) diff --git a/st.c b/st.c index fcb86a0..08adef1 100644 --- a/st.c +++ b/st.c @@ -2577,12 +2577,12 @@ draw(void) term.ocx, term.ocy, term.line[term.ocy][term.ocx]); term.ocx = cx, term.ocy = term.c.y; xfinishdraw(); - // xximspot(term.ocx, term.ocy); // disabled in wayland brach + /* xximspot(term.ocx, term.ocy); */ /* disabled in wayland brach */ } void redraw(void) { tfulldirt(); - // draw(); // disabled in wayland branch + /* draw();*/ /* Disabled in wayland */ } diff --git a/wl.c b/wl.c index 552bf33..e1d4840 100644 --- a/wl.c +++ b/wl.c @@ -176,21 +176,9 @@ typedef struct { struct timespec last; } Repeat; - - -/* TODO: Categorize these */ -static void wlselpaste(void); static int evcol(int); static int evrow(int); -static int match(uint, uint); -static char *kmap(xkb_keysym_t, uint); -static void wlresize(int, int); -static void wlinit(int, int); -static void cresize(int, int); -static void wlloadfonts(char *, double); -static void wlunloadfonts(void); -static void mousesel(int); static void wlmousereport(int, bool, int, int); static void wlmousereportbutton(uint32_t, uint32_t); static void wlmousereportmotion(wl_fixed_t, wl_fixed_t); @@ -205,10 +193,13 @@ static void ptrbutton(void *, struct wl_pointer *, uint32_t, uint32_t, uint32_t, uint32_t); static void ptraxis(void *, struct wl_pointer *, uint32_t, uint32_t, wl_fixed_t); +static void mousesel(int); +static void wlselpaste(void); static void setsel(char*, uint32_t); static inline void selwritebuf(char *, int); -/* Keyboard stuff */ +static int match(uint, uint); +static char *kmap(xkb_keysym_t, uint); static void kbdkeymap(void *, struct wl_keyboard *, uint32_t, int32_t, uint32_t); static void kbdenter(void *, struct wl_keyboard *, uint32_t, @@ -221,6 +212,8 @@ static void kbdmodifiers(void *, struct wl_keyboard *, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t); static void kbdrepeatinfo(void *, struct wl_keyboard *, int32_t, int32_t); +static void wlresize(int, int); +static void cresize(int, int); static void surfenter(void *, struct wl_surface *, struct wl_output *); static void surfleave(void *, struct wl_surface *, struct wl_output *); static void framedone(void *, struct wl_callback *, uint32_t); @@ -233,6 +226,8 @@ static void wmping(void *, struct xdg_wm_base *, uint32_t); static inline uchar sixd_to_8bit(int); static int wlloadfont(Font *, FcPattern *); static void wlunloadfont(Font *f); +static void wlloadfonts(char *, double); +static void wlunloadfonts(void); static void wlclear(int, int, int, int); static void wldraws(char *, Glyph, int, int, int, int); @@ -258,6 +253,7 @@ static void datasrcsend(void *, struct wl_data_source *, const char *, int32_t); static void datasrccancelled(void *, struct wl_data_source *); +static void wlinit(int, int); static void run(void); static void usage(void); @@ -325,13 +321,13 @@ static int oldbutton = 3; /* button event on startup: 3 = release */ void xbell(void) { - // Do nothing, no bell in wayland. + /* Do nothing, no bell in wayland. */ } void xsetpointermotion(int dummy) { - // Do nothing, not required under wayland. + /* Do nothing, not required under wayland. */ } void @@ -375,148 +371,6 @@ evrow(int y) return y / win.ch; } -int -match(uint mask, uint state) -{ - return mask == MOD_MASK_ANY || mask == (state & ~ignoremod); -} - -char* -kmap(xkb_keysym_t 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 -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; - col = MAX(1, col); - row = MAX(1, row); - - tresize(col, row); - wlresize(col, row); - ttyresize(win.tw, win.th); -} - -void -zoom(const Arg *arg) -{ - Arg larg; - - larg.f = usedfontsize + arg->f; - zoomabs(&larg); -} - -void -zoomabs(const Arg *arg) -{ - wlunloadfonts(); - wlloadfonts(usedfont, arg->f); - cresize(0, 0); - redraw(); - /* XXX: Should the window size be updated here because wayland doesn't - * * have a notion of hints? - * * xhints(); */ -} - -void -zoomreset(const Arg *arg) -{ - Arg larg; - if (defaultfontsize > 0) { - larg.f = defaultfontsize; - zoomabs(&larg); - } -} - -void -xclipcopy(void) -{ - clipcopy(NULL); -} - -void -clipcopy(const Arg * dummy) -{ - // TODO: Implement this! -} - -void -clippaste(const Arg * dummy) -{ - // TODO: Implement this! -} - -void -selpaste(const Arg * dummy) -{ - // TODO: Implement this! -} - -void -xsetsel(char * buf) -{ - setsel(buf, wl.globalserial); -} - -void -mousesel(int done) -{ - int type, seltype = SEL_REGULAR; - uint state = wl.xkb.mods & ~forceselmod; - - for (type = 1; type < LEN(selmasks); ++type) { - if (match(selmasks[type], state)) { - seltype = type; - break; - } - } - - selextend(evcol(wl.px), evrow(wl.py), seltype, done); - if (done) - setsel(getsel(), wl.globalserial); -} - void wlmousereport(int button, bool release, int x, int y) { @@ -706,6 +560,25 @@ ptraxis(void * data, struct wl_pointer * pointer, uint32_t time, uint32_t axis, } } +void +mousesel(int done) +{ + int type, seltype = SEL_REGULAR; + uint state = wl.xkb.mods & ~forceselmod; + + for (type = 1; type < LEN(selmasks); ++type) { + if (match(selmasks[type], state)) { + seltype = type; + break; + } + } + + selextend(evcol(wl.px), evrow(wl.py), seltype, done); + if (done) + setsel(getsel(), wl.globalserial); +} + + void setsel(char *str, uint32_t serial) { @@ -779,6 +652,80 @@ wlselpaste(void) } } +void +xclipcopy(void) +{ + clipcopy(NULL); +} + +void +clipcopy(const Arg * dummy) +{ + setsel(getsel(), wl.globalserial); +} + +void +clippaste(const Arg * dummy) +{ + wlselpaste(); +} + +void +selpaste(const Arg * dummy) +{ + wlselpaste(); +} + +void +xsetsel(char * buf) +{ + setsel(buf, wl.globalserial); +} + +int +match(uint mask, uint state) +{ + return mask == MOD_MASK_ANY || mask == (state & ~ignoremod); +} + +char* +kmap(xkb_keysym_t 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 kbdkeymap(void *data, struct wl_keyboard *keyboard, uint32_t format, int32_t fd, uint32_t size) @@ -942,6 +889,58 @@ kbdrepeatinfo(void *data, struct wl_keyboard *keyboard, int32_t rate, keyrepeatinterval = 1000 / rate; } +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; + col = MAX(1, col); + row = MAX(1, row); + + tresize(col, row); + wlresize(col, row); + ttyresize(win.tw, win.th); +} + +void +zoom(const Arg *arg) +{ + Arg larg; + + larg.f = usedfontsize + arg->f; + zoomabs(&larg); +} + +void +zoomabs(const Arg *arg) +{ + wlunloadfonts(); + wlloadfonts(usedfont, arg->f); + cresize(0, 0); + redraw(); + /* XXX: Should the window size be updated here because wayland doesn't + * * have a notion of hints? + * * xhints(); */ +} + +void +zoomreset(const Arg *arg) +{ + Arg larg; + if (defaultfontsize > 0) { + larg.f = defaultfontsize; + zoomabs(&larg); + } +} + + void wlresize(int col, int row) { @@ -1539,9 +1538,6 @@ wldraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) if (frclen >= frccap) { frccap += 16; frc = xrealloc(frc, frccap * sizeof(Fontcache)); - // frclen = LEN(frc) - 1; - // wld_font_close(frc[frclen].font); - // frc[frclen].unicodep = 0; } frc[frclen].font = wld_font_open_pattern(wld.fontctx,