44 Commits

Author SHA1 Message Date
  Tovi Jaeschke-Rogers 89b6a295f7 feat: colourscheme 5 days ago
  Lucas de Sena a0274bc20e fix BadMatch error when embedding on some windows 8 months ago
  Hiltjo Posthuma 5dbcca4926 support colons in SGR character attributes 11 months ago
  Hiltjo Posthuma d63b9eb902 bump version to 0.9.2 1 year ago
  DOGMAN 497a756382 Reset title when an empty title string is given 1 year ago
  Hiltjo Posthuma 8c68ec5241 Revert "Fix cursor move with wide glyphs" 1 year ago
  Hiltjo Posthuma 5ce9716281 bump version to 0.9.1 1 year ago
  Hiltjo Posthuma f20e169a20 config.def.h: improve latency for the default configuration 1 year ago
  Tommi Hirvola 95f22c5305 set upper limit for REP escape sequence argument 1 year ago
  Quentin Rameau 7473a8d1a5 Fix cursor move with wide glyphs 1 year ago
  Tim Culverhouse a3f7420310 csi: check for private marker in 'S' case 1 year ago
  Peter Hofmann 9846a56bd7 Add terminfo entries for bracketed paste mode 2 years ago
  Peter Hofmann 559fdc2786 Unhide cursor on RIS (\033c) 2 years ago
  Peter Hofmann 8abe4bcb41 Fix wide glyphs breaking "nowrap" mode 2 years ago
  Peter Hofmann 2fc7e532b2 Don't scroll selection on the other screen 2 years ago
  Peter Hofmann a6bbc0c96b Fix bounds checks of dc.col 2 years ago
  Hiltjo Posthuma eb3b894f40 Makefile: remove the options target 2 years ago
  Shi Tian 3a6d6d7401 Fix for wide character being incorrectly cleared on MODE_INSERT 2 years ago
  Hiltjo Posthuma 211964d56e ignore C1 control characters in UTF-8 mode 2 years ago
  Adam Price f17abd25b3 Add support for DSR response "OK" escape sequence 2 years ago
  Hiltjo Posthuma 7e8050cc62 Fixed OSC color reset without parameter->resets all colors 2 years ago
  Hiltjo Posthuma e5e959835b fix buffer overflow when handling long composed input 2 years ago
  Hiltjo Posthuma 68d1ad9b54 bump version to 0.9 3 years ago
  Hiltjo Posthuma 0008519903 FAQ: document the color emojis crash issue which affected some systems is fixed 3 years ago
  Tom Schwindl 72fd32736a st: use `void' to indicate an empty parameter list 3 years ago
  Hiltjo Posthuma baa9357e96 Makefile: add manual path for OpenBSD 3 years ago
  NRK 8629d9a1da code-golfing: cleanup osc color related code 3 years ago
  NRK ef0551932f base64_digits: reduce scope, implicit zero, +1 size 3 years ago
  NRK af3bb68add avoid potential UB when using isprint() 3 years ago
  Zacchary Dempsey-Plante 2aefa348ba make underlines and strikethroughs respect `chscale` 3 years ago
  Santtu Lakkala e823e2308f Delay redrawals on palette changes 3 years ago
  Hiltjo Posthuma 2c5edf28ec X10/SGR mouse: use alt as meta key instead of super/windows key 3 years ago
  Hiltjo Posthuma b1d97fec47 LICENSE: bump year 3 years ago
  robert ea7cd7b62f Fix mousereport 3 years ago
  Hiltjo Posthuma 7fb0c0cc68 bump version to 0.8.5 3 years ago
  Hiltjo Posthuma 7e1c68f25d FAQ: fix a typo, patch -> path 3 years ago
  jamin 65f1dc4283 Fix overtyping wide characters. 3 years ago
  Jochen Sprickerhof a0467c802d Fix null pointer access in strhandle 3 years ago
  Hiltjo Posthuma 273db5ceaf follow-up fix for OSC color sequences, return 3 years ago
  Raheman Vaiya 8e31030390 Add support for OSC color sequences 3 years ago
  Hiltjo Posthuma 2f6e597ed8 fix possible rare crash when Xutf8TextPropertyToTextList fails 4 years ago
  Koichi Murase 1d3142da96 fix a problem that the standard streams are unexpectedly closed 4 years ago
  Petar Kapriš 2ec571a30c Add 14th bit to XK_SWITCH_MOD bitmask 4 years ago
  Markus F.X.J. Oberhumer 4536f46cff Mild const-correctness improvements. 4 years ago
11 changed files with 723 additions and 123 deletions
Split View
  1. +5
    -2
      FAQ
  2. +1
    -1
      LICENSE
  3. +2
    -8
      Makefile
  4. +6
    -4
      config.def.h
  5. +478
    -0
      config.h
  6. +2
    -1
      config.mk
  7. +125
    -52
      st.c
  8. +3
    -2
      st.h
  9. +4
    -0
      st.info
  10. +1
    -0
      win.h
  11. +96
    -53
      x.c

+ 5
- 2
FAQ View File

@ -29,8 +29,8 @@ you can manually run `tic -sx st.info`.
## I would like to have utmp and/or scroll functionality by default
You can add the absolute patch of both programs in your config.h
file. You only have to modify the value of utmp and scroll variables.
You can add the absolute path of both programs in your config.h file. You only
have to modify the value of utmp and scroll variables.
## Why doesn't the Del key work in some programs?
@ -248,3 +248,6 @@ fonts:
Please don't bother reporting this bug to st, but notify the upstream Xft
developers about fixing this bug.
As of 2022-09-05 this now seems to be finally fixed in libXft 2.3.5:
https://gitlab.freedesktop.org/xorg/lib/libxft/-/blob/libXft-2.3.5/NEWS

+ 1
- 1
LICENSE View File

@ -1,6 +1,6 @@
MIT/X Consortium License
© 2014-2020 Hiltjo Posthuma <hiltjo at codemadness dot org>
© 2014-2022 Hiltjo Posthuma <hiltjo at codemadness dot org>
© 2018 Devin J. Pohly <djpohly at gmail dot com>
© 2014-2017 Quentin Rameau <quinq at fifth dot space>
© 2009-2012 Aurélien APTEL <aurelien dot aptel at gmail dot com>


+ 2
- 8
Makefile View File

@ -7,13 +7,7 @@ include config.mk
SRC = st.c x.c
OBJ = $(SRC:.c=.o)
all: options st
options:
@echo st build options:
@echo "CFLAGS = $(STCFLAGS)"
@echo "LDFLAGS = $(STLDFLAGS)"
@echo "CC = $(CC)"
all: st
config.h:
cp config.def.h config.h
@ -54,4 +48,4 @@ uninstall:
rm -f $(DESTDIR)$(PREFIX)/bin/st
rm -f $(DESTDIR)$(MANPREFIX)/man1/st.1
.PHONY: all options clean dist install uninstall
.PHONY: all clean dist install uninstall

+ 6
- 4
config.def.h View File

@ -53,7 +53,7 @@ int allowwindowops = 0;
* near minlatency, but it waits longer for slow updates to avoid partial draw.
* low minlatency will tear/flicker more, as it can "detect" idle too early.
*/
static double minlatency = 8;
static double minlatency = 2;
static double maxlatency = 33;
/*
@ -120,6 +120,8 @@ static const char *colorname[] = {
/* more colors can be added after 255 to use with DefaultXX */
"#cccccc",
"#555555",
"gray90", /* default foreground colour */
"black", /* default background colour */
};
@ -127,9 +129,9 @@ static const char *colorname[] = {
* Default colors (colorname index)
* foreground, background, cursor, reverse cursor
*/
unsigned int defaultfg = 7;
unsigned int defaultbg = 0;
static unsigned int defaultcs = 256;
unsigned int defaultfg = 258;
unsigned int defaultbg = 259;
unsigned int defaultcs = 256;
static unsigned int defaultrcs = 257;
/*


+ 478
- 0
config.h View File

@ -0,0 +1,478 @@
/* See LICENSE file for copyright and license details. */
/*
* appearance
*
* font: see http://freedesktop.org/software/fontconfig/fontconfig-user.html
*/
static char *font = "JetBrains Mono Nerd Font:pixelsize=20:antialias=true:autohint=true";
static int borderpx = 2;
/*
* What program is execed by st depends of these precedence rules:
* 1: program passed with -e
* 2: scroll and/or utmp
* 3: SHELL environment variable
* 4: value of shell in /etc/passwd
* 5: value of shell in config.h
*/
static char *shell = "/bin/sh";
char *utmp = NULL;
/* scroll program: to enable use a string like "scroll" */
char *scroll = NULL;
char *stty_args = "stty raw pass8 nl -echo -iexten -cstopb 38400";
/* identification sequence returned in DA and DECID */
char *vtiden = "\033[?6c";
/* Kerning / character bounding-box multipliers */
static float cwscale = 1.0;
static float chscale = 1.0;
/*
* word delimiter string
*
* More advanced example: L" `'\"()[]{}"
*/
wchar_t *worddelimiters = L" ";
/* selection timeouts (in milliseconds) */
static unsigned int doubleclicktimeout = 300;
static unsigned int tripleclicktimeout = 600;
/* alt screens */
int allowaltscreen = 1;
/* allow certain non-interactive (insecure) window operations such as:
setting the clipboard text */
int allowwindowops = 0;
/*
* draw latency range in ms - from new content/keypress/etc until drawing.
* within this range, st draws when content stops arriving (idle). mostly it's
* near minlatency, but it waits longer for slow updates to avoid partial draw.
* low minlatency will tear/flicker more, as it can "detect" idle too early.
*/
static double minlatency = 2;
static double maxlatency = 33;
/*
* blinking timeout (set to 0 to disable blinking) for the terminal blinking
* attribute.
*/
static unsigned int blinktimeout = 800;
/*
* thickness of underline and bar cursors
*/
static unsigned int cursorthickness = 2;
/*
* bell volume. It must be a value between -100 and 100. Use 0 for disabling
* it
*/
static int bellvolume = 0;
/* default TERM value */
char *termname = "st-256color";
/*
* spaces per tab
*
* When you are changing this value, don't forget to adapt the »it« value in
* the st.info and appropriately install the st.info in the environment where
* you use this st version.
*
* it#$tabspaces,
*
* Secondly make sure your kernel is not expanding tabs. When running `stty
* -a` »tab0« should appear. You can tell the terminal to not expand tabs by
* running following command:
*
* stty tabs
*/
unsigned int tabspaces = 4;
/* Terminal colors (16 first used in escape sequence) */
static const char *colorname[] = {
/* 8 normal colors */
[0] = "#090618", /* black */
[1] = "#c34043", /* red */
[2] = "#76946a", /* green */
[3] = "#c0a36e", /* yellow */
[4] = "#7e9cd8", /* blue */
[5] = "#957fb8", /* magenta */
[6] = "#6a9589", /* cyan */
[7] = "#c8c093", /* white */
/* 8 bright colors */
[8] = "#727169", /* black */
[9] = "#e82424", /* red */
[10] = "#98bb6c", /* green */
[11] = "#e6c384", /* yellow */
[12] = "#7fb4ca", /* blue */
[13] = "#938aa9", /* magenta */
[14] = "#7aa89f", /* cyan */
[15] = "#dcd7ba", /* white */
/* special colors */
[256] = "#1f1f28", /* background */
[257] = "#dcd7ba", /* foreground */
};
/*
* Default colors (colorname index)
* foreground, background, cursor, reverse cursor
*/
unsigned int defaultfg = 257;
unsigned int defaultbg = 256;
unsigned int defaultcs = 257;
static unsigned int defaultrcs = 257;
/*
* Colors used, when the specific fg == defaultfg. So in reverse mode this
* will reverse too. Another logic would only make the simple feature too
* complex.
*/
static unsigned int defaultitalic = 7;
static unsigned int defaultunderline = 7;
/*
* Default shape of cursor
* 2: Block ("")
* 4: Underline ("_")
* 6: Bar ("|")
* 7: Snowman ("")
*/
static unsigned int cursorshape = 2;
/*
* Default columns and rows numbers
*/
static unsigned int cols = 80;
static unsigned int rows = 24;
/*
* Default colour and shape of the mouse cursor
*/
static unsigned int mouseshape = XC_xterm;
static unsigned int mousefg = 7;
static unsigned int mousebg = 0;
/*
* Color used to display font attributes when fontconfig selected a font which
* doesn't match the ones requested.
*/
static unsigned int defaultattr = 11;
/*
* Force mouse select/shortcuts while mask is active (when MODE_MOUSE is set).
* Note that if you want to use ShiftMask with selmasks, set this to an other
* modifier, set to 0 to not use it.
*/
static uint forcemousemod = ShiftMask;
/*
* Internal mouse shortcuts.
* Beware that overloading Button1 will disable the selection.
*/
static MouseShortcut mshortcuts[] = {
/* mask button function argument release */
{ XK_ANY_MOD, Button2, selpaste, {.i = 0}, 1 },
{ ShiftMask, Button4, ttysend, {.s = "\033[5;2~"} },
{ XK_ANY_MOD, Button4, ttysend, {.s = "\031"} },
{ ShiftMask, Button5, ttysend, {.s = "\033[6;2~"} },
{ XK_ANY_MOD, Button5, ttysend, {.s = "\005"} },
};
/* Internal keyboard shortcuts. */
#define MODKEY Mod1Mask
#define TERMMOD (ControlMask|ShiftMask)
static Shortcut shortcuts[] = {
/* mask keysym function argument */
{ XK_ANY_MOD, XK_Break, sendbreak, {.i = 0} },
{ ControlMask, XK_Print, toggleprinter, {.i = 0} },
{ ShiftMask, XK_Print, printscreen, {.i = 0} },
{ XK_ANY_MOD, XK_Print, printsel, {.i = 0} },
{ TERMMOD, XK_Prior, zoom, {.f = +1} },
{ TERMMOD, XK_Next, zoom, {.f = -1} },
{ TERMMOD, XK_Home, zoomreset, {.f = 0} },
{ TERMMOD, XK_C, clipcopy, {.i = 0} },
{ TERMMOD, XK_V, clippaste, {.i = 0} },
{ TERMMOD, XK_Y, selpaste, {.i = 0} },
{ ShiftMask, XK_Insert, selpaste, {.i = 0} },
{ TERMMOD, XK_Num_Lock, numlock, {.i = 0} },
};
/*
* 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)
* appkey value:
* * 0: no value
* * > 0: keypad application mode enabled
* * = 2: term.numlock = 1
* * < 0: keypad application mode disabled
* appcursor value:
* * 0: no value
* * > 0: cursor application mode enabled
* * < 0: cursor application mode disabled
*
* Be careful with the order of the definitions because st searches in
* this table sequentially, so any XK_ANY_MOD must be in the last
* position for a key.
*/
/*
* If you want keys other than the X11 function keys (0xFD00 - 0xFFFF)
* to be mapped below, add them to this array.
*/
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.
*/
static uint ignoremod = Mod2Mask|XK_SWITCH_MOD;
/*
* This is the huge key array which defines all compatibility to the Linux
* world. Please decide about changes wisely.
*/
static Key key[] = {
/* keysym mask string appkey appcursor */
{ XK_KP_Home, ShiftMask, "\033[2J", 0, -1},
{ XK_KP_Home, ShiftMask, "\033[1;2H", 0, +1},
{ XK_KP_Home, XK_ANY_MOD, "\033[H", 0, -1},
{ XK_KP_Home, XK_ANY_MOD, "\033[1~", 0, +1},
{ XK_KP_Up, XK_ANY_MOD, "\033Ox", +1, 0},
{ XK_KP_Up, XK_ANY_MOD, "\033[A", 0, -1},
{ XK_KP_Up, XK_ANY_MOD, "\033OA", 0, +1},
{ XK_KP_Down, XK_ANY_MOD, "\033Or", +1, 0},
{ XK_KP_Down, XK_ANY_MOD, "\033[B", 0, -1},
{ XK_KP_Down, XK_ANY_MOD, "\033OB", 0, +1},
{ XK_KP_Left, XK_ANY_MOD, "\033Ot", +1, 0},
{ XK_KP_Left, XK_ANY_MOD, "\033[D", 0, -1},
{ XK_KP_Left, XK_ANY_MOD, "\033OD", 0, +1},
{ XK_KP_Right, XK_ANY_MOD, "\033Ov", +1, 0},
{ XK_KP_Right, XK_ANY_MOD, "\033[C", 0, -1},
{ XK_KP_Right, XK_ANY_MOD, "\033OC", 0, +1},
{ XK_KP_Prior, ShiftMask, "\033[5;2~", 0, 0},
{ XK_KP_Prior, XK_ANY_MOD, "\033[5~", 0, 0},
{ XK_KP_Begin, XK_ANY_MOD, "\033[E", 0, 0},
{ XK_KP_End, ControlMask, "\033[J", -1, 0},
{ XK_KP_End, ControlMask, "\033[1;5F", +1, 0},
{ XK_KP_End, ShiftMask, "\033[K", -1, 0},
{ XK_KP_End, ShiftMask, "\033[1;2F", +1, 0},
{ XK_KP_End, XK_ANY_MOD, "\033[4~", 0, 0},
{ XK_KP_Next, ShiftMask, "\033[6;2~", 0, 0},
{ XK_KP_Next, XK_ANY_MOD, "\033[6~", 0, 0},
{ XK_KP_Insert, ShiftMask, "\033[2;2~", +1, 0},
{ XK_KP_Insert, ShiftMask, "\033[4l", -1, 0},
{ XK_KP_Insert, ControlMask, "\033[L", -1, 0},
{ XK_KP_Insert, ControlMask, "\033[2;5~", +1, 0},
{ XK_KP_Insert, XK_ANY_MOD, "\033[4h", -1, 0},
{ XK_KP_Insert, XK_ANY_MOD, "\033[2~", +1, 0},
{ XK_KP_Delete, ControlMask, "\033[M", -1, 0},
{ XK_KP_Delete, ControlMask, "\033[3;5~", +1, 0},
{ XK_KP_Delete, ShiftMask, "\033[2K", -1, 0},
{ XK_KP_Delete, ShiftMask, "\033[3;2~", +1, 0},
{ XK_KP_Delete, XK_ANY_MOD, "\033[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},
};
/*
* Selection types' masks.
* Use the same masks as usual.
* Button1Mask is always unset, to make masks match between ButtonPress.
* ButtonRelease and MotionNotify.
* If no match is found, regular selection is used.
*/
static uint selmasks[] = {
[SEL_RECTANGULAR] = Mod1Mask,
};
/*
* Printable characters in ASCII, used to estimate the advance width
* of single wide characters.
*/
static char ascii_printable[] =
" !\"#$%&'()*+,-./0123456789:;<=>?"
"@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_"
"`abcdefghijklmnopqrstuvwxyz{|}~";

+ 2
- 1
config.mk View File

@ -1,5 +1,5 @@
# st version
VERSION = 0.8.4
VERSION = 0.9.2
# Customize below to fit your system
@ -30,6 +30,7 @@ STLDFLAGS = $(LIBS) $(LDFLAGS)
#LIBS = -L$(X11LIB) -lm -lX11 -lutil -lXft \
# `$(PKG_CONFIG) --libs fontconfig` \
# `$(PKG_CONFIG) --libs freetype2`
#MANPREFIX = ${PREFIX}/man
# compiler and linker
# CC = c99

+ 125
- 52
st.c View File

@ -161,6 +161,7 @@ static void csidump(void);
static void csihandle(void);
static void csiparse(void);
static void csireset(void);
static void osc_color_response(int, int, int);
static int eschandle(uchar);
static void strdump(void);
static void strhandle(void);
@ -186,18 +187,18 @@ static void tputc(Rune);
static void treset(void);
static void tscrollup(int, int);
static void tscrolldown(int, int);
static void tsetattr(int *, int);
static void tsetchar(Rune, Glyph *, int, int);
static void tsetattr(const int *, int);
static void tsetchar(Rune, const Glyph *, int, int);
static void tsetdirt(int, int);
static void tsetscroll(int, int);
static void tswapscreen(void);
static void tsetmode(int, int, int *, int);
static void tsetmode(int, int, const int *, int);
static int twrite(const char *, int, int);
static void tfulldirt(void);
static void tcontrolcode(uchar );
static void tdectest(char );
static void tdefutf8(char);
static int32_t tdefcolor(int *, int *, int);
static int32_t tdefcolor(const int *, int *, int);
static void tdeftran(char);
static void tstrsequence(uchar);
@ -226,10 +227,10 @@ 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};
static Rune utfmin[UTF_SIZ + 1] = { 0, 0, 0x80, 0x800, 0x10000};
static Rune utfmax[UTF_SIZ + 1] = {0x10FFFF, 0x7F, 0x7FF, 0xFFFF, 0x10FFFF};
static const uchar utfbyte[UTF_SIZ + 1] = {0x80, 0, 0xC0, 0xE0, 0xF0};
static const uchar utfmask[UTF_SIZ + 1] = {0xC0, 0x80, 0xE0, 0xF0, 0xF8};
static const Rune utfmin[UTF_SIZ + 1] = { 0, 0, 0x80, 0x800, 0x10000};
static const Rune utfmax[UTF_SIZ + 1] = {0x10FFFF, 0x7F, 0x7FF, 0xFFFF, 0x10FFFF};
ssize_t
xwrite(int fd, const char *s, size_t len)
@ -269,12 +270,14 @@ xrealloc(void *p, size_t len)
}
char *
xstrdup(char *s)
xstrdup(const char *s)
{
if ((s = strdup(s)) == NULL)
char *p;
if ((p = strdup(s)) == NULL)
die("strdup: %s\n", strerror(errno));
return s;
return p;
}
size_t
@ -347,25 +350,10 @@ 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))
while (**src && !isprint((unsigned char)**src))
(*src)++;
return **src ? *((*src)++) : '='; /* emulate padding if string ends */
}
@ -375,6 +363,13 @@ base64dec(const char *src)
{
size_t in_len = strlen(src);
char *result, *dst;
static const char base64_digits[256] = {
[43] = 62, 0, 0, 0, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61,
0, 0, 0, -1, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 0, 0, 0, 0,
0, 0, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39,
40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51
};
if (in_len % 4)
in_len += 4 - (in_len % 4);
@ -518,7 +513,7 @@ selsnap(int *x, int *y, int direction)
{
int newx, newy, xt, yt;
int delim, prevdelim;
Glyph *gp, *prevgp;
const Glyph *gp, *prevgp;
switch (sel.snap) {
case SNAP_WORD:
@ -591,7 +586,7 @@ getsel(void)
{
char *str, *ptr;
int y, bufsize, lastx, linelen;
Glyph *gp, *last;
const Glyph *gp, *last;
if (sel.ob.x == -1)
return NULL;
@ -758,7 +753,7 @@ stty(char **args)
}
int
ttynew(char *line, char *cmd, char *out, char **args)
ttynew(const char *line, char *cmd, const char *out, char **args)
{
int m, s;
@ -791,14 +786,15 @@ ttynew(char *line, char *cmd, char *out, char **args)
break;
case 0:
close(iofd);
close(m);
setsid(); /* create a new process group */
dup2(s, 0);
dup2(s, 1);
dup2(s, 2);
if (ioctl(s, TIOCSCTTY, NULL) < 0)
die("ioctl TIOCSCTTY failed: %s\n", strerror(errno));
close(s);
close(m);
if (s > 2)
close(s);
#ifdef __OpenBSD__
if (pledge("stdio getpw proc exec", NULL) == -1)
die("pledge\n");
@ -943,7 +939,7 @@ ttyresize(int tw, int th)
}
void
ttyhangup()
ttyhangup(void)
{
/* Send SIGHUP to shell */
kill(pid, SIGHUP);
@ -1101,7 +1097,7 @@ tscrollup(int orig, int n)
void
selscroll(int orig, int n)
{
if (sel.ob.x == -1)
if (sel.ob.x == -1 || sel.alt != IS_SET(MODE_ALTSCREEN))
return;
if (BETWEEN(sel.nb.y, orig, term.bot) != BETWEEN(sel.ne.y, orig, term.bot)) {
@ -1136,6 +1132,7 @@ csiparse(void)
{
char *p = csiescseq.buf, *np;
long int v;
int sep = ';'; /* colon or semi-colon, but not both */
csiescseq.narg = 0;
if (*p == '?') {
@ -1153,7 +1150,9 @@ csiparse(void)
v = -1;
csiescseq.arg[csiescseq.narg++] = v;
p = np;
if (*p != ';' || csiescseq.narg == ESC_ARG_SIZ)
if (sep == ';' && *p == ':')
sep = ':'; /* allow override to colon once */
if (*p != sep || csiescseq.narg == ESC_ARG_SIZ)
break;
p++;
}
@ -1186,9 +1185,9 @@ tmoveto(int x, int y)
}
void
tsetchar(Rune u, Glyph *attr, int x, int y)
tsetchar(Rune u, const Glyph *attr, int x, int y)
{
static char *vt100_0[62] = { /* 0x41 - 0x7e */
static const char *vt100_0[62] = { /* 0x41 - 0x7e */
"", "", "", "", "", "", "", /* A - G */
0, 0, 0, 0, 0, 0, 0, 0, /* H - O */
0, 0, 0, 0, 0, 0, 0, 0, /* P - W */
@ -1300,7 +1299,7 @@ tdeleteline(int n)
}
int32_t
tdefcolor(int *attr, int *npar, int l)
tdefcolor(const int *attr, int *npar, int l)
{
int32_t idx = -1;
uint r, g, b;
@ -1350,7 +1349,7 @@ tdefcolor(int *attr, int *npar, int l)
}
void
tsetattr(int *attr, int l)
tsetattr(const int *attr, int l)
{
int i;
int32_t idx;
@ -1468,9 +1467,9 @@ tsetscroll(int t, int b)
}
void
tsetmode(int priv, int set, int *args, int narg)
tsetmode(int priv, int set, const int *args, int narg)
{
int alt, *lim;
int alt; const int *lim;
for (lim = args + narg; args < lim; ++args) {
if (priv) {
@ -1647,7 +1646,7 @@ csihandle(void)
ttywrite(vtiden, strlen(vtiden), 0);
break;
case 'b': /* REP -- if last char is printable print it <n> more times */
DEFAULT(csiescseq.arg[0], 1);
LIMIT(csiescseq.arg[0], 1, 65535);
if (term.lastc)
while (csiescseq.arg[0]-- > 0)
tputc(term.lastc);
@ -1732,6 +1731,7 @@ csihandle(void)
}
break;
case 'S': /* SU -- Scroll <n> line up */
if (csiescseq.priv) break;
DEFAULT(csiescseq.arg[0], 1);
tscrollup(term.top, csiescseq.arg[0]);
break;
@ -1773,11 +1773,18 @@ csihandle(void)
case 'm': /* SGR -- Terminal attribute (color) */
tsetattr(csiescseq.arg, csiescseq.narg);
break;
case 'n': /* DSR – Device Status Report (cursor position) */
if (csiescseq.arg[0] == 6) {
case 'n': /* DSR -- Device Status Report */
switch (csiescseq.arg[0]) {
case 5: /* Status Report "OK" `0n` */
ttywrite("\033[0n", sizeof("\033[0n") - 1, 0);
break;
case 6: /* Report Cursor Position (CPR) "<row>;<column>R" */
len = snprintf(buf, sizeof(buf), "\033[%i;%iR",
term.c.y+1, term.c.x+1);
term.c.y+1, term.c.x+1);
ttywrite(buf, len, 0);
break;
default:
goto unknown;
}
break;
case 'r': /* DECSTBM -- Set Scrolling Region */
@ -1839,11 +1846,41 @@ csireset(void)
memset(&csiescseq, 0, sizeof(csiescseq));
}
void
osc_color_response(int num, int index, int is_osc4)
{
int n;
char buf[32];
unsigned char r, g, b;
if (xgetcolor(is_osc4 ? num : index, &r, &g, &b)) {
fprintf(stderr, "erresc: failed to fetch %s color %d\n",
is_osc4 ? "osc4" : "osc",
is_osc4 ? num : index);
return;
}
n = snprintf(buf, sizeof buf, "\033]%s%d;rgb:%02x%02x/%02x%02x/%02x%02x\007",
is_osc4 ? "4;" : "", num, r, r, g, g, b, b);
if (n < 0 || n >= sizeof(buf)) {
fprintf(stderr, "error: %s while printing %s response\n",
n < 0 ? "snprintf failed" : "truncation occurred",
is_osc4 ? "osc4" : "osc");
} else {
ttywrite(buf, n, 1);
}
}
void
strhandle(void)
{
char *p = NULL, *dec;
int j, narg, par;
const struct { int idx; char *str; } osc_table[] = {
{ defaultfg, "foreground" },
{ defaultbg, "background" },
{ defaultcs, "cursor" }
};
term.esc &= ~(ESC_STR_END|ESC_STR);
strparse();
@ -1877,16 +1914,39 @@ strhandle(void)
}
}
return;
case 10:
case 11:
case 12:
if (narg < 2)
break;
p = strescseq.args[1];
if ((j = par - 10) < 0 || j >= LEN(osc_table))
break; /* shouldn't be possible */
if (!strcmp(p, "?")) {
osc_color_response(par, osc_table[j].idx, 0);
} else if (xsetcolorname(osc_table[j].idx, p)) {
fprintf(stderr, "erresc: invalid %s color: %s\n",
osc_table[j].str, p);
} else {
tfulldirt();
}
return;
case 4: /* color set */
if (narg < 3)
break;
p = strescseq.args[2];
/* FALLTHROUGH */
case 104: /* color reset, here p = NULL */
case 104: /* color reset */
j = (narg > 1) ? atoi(strescseq.args[1]) : -1;
if (xsetcolorname(j, p)) {
if (par == 104 && narg <= 1)
if (p && !strcmp(p, "?")) {
osc_color_response(j, 0, 1);
} else if (xsetcolorname(j, p)) {
if (par == 104 && narg <= 1) {
xloadcols();
return; /* color reset without parameter */
}
fprintf(stderr, "erresc: invalid color j=%d, p=%s\n",
j, p ? p : "(null)");
} else {
@ -1894,7 +1954,7 @@ strhandle(void)
* TODO if defaultbg color is changed, borders
* are dirty
*/
redraw();
tfulldirt();
}
return;
}
@ -2020,7 +2080,7 @@ void
tdumpline(int n)
{
char buf[UTF_SIZ];
Glyph *bp, *end;
const Glyph *bp, *end;
bp = &term.line[n][0];
end = &bp[MIN(tlinelen(n), term.col) - 1];
@ -2274,6 +2334,7 @@ eschandle(uchar ascii)
treset();
resettitle();
xloadcols();
xsetmode(0, MODE_HIDE);
break;
case '=': /* DECPAM -- Application keypad */
xsetmode(1, MODE_APPKEYPAD);
@ -2366,6 +2427,9 @@ check_control_code:
* they must not cause conflicts with sequences.
*/
if (control) {
/* in UTF-8 mode ignore handling C1 control characters */
if (IS_SET(MODE_UTF8) && ISCONTROLC1(u))
return;
tcontrolcode(u);
/*
* control codes are not shown ever
@ -2412,11 +2476,16 @@ check_control_code:
gp = &term.line[term.c.y][term.c.x];
}
if (IS_SET(MODE_INSERT) && term.c.x+width < term.col)
if (IS_SET(MODE_INSERT) && term.c.x+width < term.col) {
memmove(gp+width, gp, (term.col - term.c.x - width) * sizeof(Glyph));
gp->mode &= ~ATTR_WIDE;
}
if (term.c.x+width > term.col) {
tnewline(1);
if (IS_SET(MODE_WRAP))
tnewline(1);
else
tmoveto(term.col - width, term.c.y);
gp = &term.line[term.c.y][term.c.x];
}
@ -2426,6 +2495,10 @@ check_control_code:
if (width == 2) {
gp->mode |= ATTR_WIDE;
if (term.c.x+1 < term.col) {
if (gp[1].mode == ATTR_WIDE && term.c.x+2 < term.col) {
gp[2].u = ' ';
gp[2].mode &= ~ATTR_WDUMMY;
}
gp[1].u = '\0';
gp[1].mode = ATTR_WDUMMY;
}


+ 3
- 2
st.h View File

@ -91,7 +91,7 @@ void tnew(int, int);
void tresize(int, int);
void tsetdirtattr(int);
void ttyhangup(void);
int ttynew(char *, char *, char *, char **);
int ttynew(const char *, char *, const char *, char **);
size_t ttyread(void);
void ttyresize(int, int);
void ttywrite(const char *, size_t, int);
@ -109,7 +109,7 @@ size_t utf8encode(Rune, char *);
void *xmalloc(size_t);
void *xrealloc(void *, size_t);
char *xstrdup(char *);
char *xstrdup(const char *);
/* config.h globals */
extern char *utmp;
@ -123,3 +123,4 @@ extern char *termname;
extern unsigned int tabspaces;
extern unsigned int defaultfg;
extern unsigned int defaultbg;
extern unsigned int defaultcs;

+ 4
- 0
st.info View File

@ -184,6 +184,10 @@ st-mono| simpleterm monocolor,
# XTerm extensions
rmxx=\E[29m,
smxx=\E[9m,
BE=\E[?2004h,
BD=\E[?2004l,
PS=\E[200~,
PE=\E[201~,
# disabled rep for now: causes some issues with older ncurses versions.
# rep=%p1%c\E[%p2%{1}%-%db,
# tmux extensions, see TERMINFO EXTENSIONS in tmux(1)


+ 1
- 0
win.h View File

@ -30,6 +30,7 @@ void xdrawline(Line, int, int, int);
void xfinishdraw(void);
void xloadcols(void);
int xsetcolorname(int, const char *);
int xgetcolor(int, unsigned char *, unsigned char *, unsigned char *);
void xseticontitle(char *);
void xsettitle(char *);
int xsetcursor(int);


+ 96
- 53
x.c View File

@ -48,7 +48,7 @@ typedef struct {
/* X modifiers */
#define XK_ANY_MOD UINT_MAX
#define XK_NO_MOD 0
#define XK_SWITCH_MOD (1<<13)
#define XK_SWITCH_MOD (1<<13|1<<14)
/* function definitions used in config.h */
static void clipcopy(const Arg *);
@ -156,7 +156,7 @@ 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 xloadfonts(const char *, double);
static void xunloadfont(Font *);
static void xunloadfonts(void);
static void xsetenv(void);
@ -252,7 +252,7 @@ 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 uint buttons; /* bit field of pressed buttons */
void
clipcopy(const Arg *dummy)
@ -364,61 +364,68 @@ mousesel(XEvent *e, int done)
void
mousereport(XEvent *e)
{
int len, x = evcol(e), y = evrow(e),
button = e->xbutton.button, state = e->xbutton.state;
int len, btn, code;
int x = evcol(e), y = evrow(e);
int state = e->xbutton.state;
char buf[40];
static int ox, oy;
/* from urxvt */
if (e->xbutton.type == MotionNotify) {
if (e->type == MotionNotify) {
if (x == ox && y == oy)
return;
if (!IS_SET(MODE_MOUSEMOTION) && !IS_SET(MODE_MOUSEMANY))
return;
/* MOUSE_MOTION: no reporting if no button is pressed */
if (IS_SET(MODE_MOUSEMOTION) && oldbutton == 3)
/* MODE_MOUSEMOTION: no reporting if no button is pressed */
if (IS_SET(MODE_MOUSEMOTION) && buttons == 0)
return;
button = oldbutton + 32;
ox = x;
oy = y;
/* Set btn to lowest-numbered pressed button, or 12 if no
* buttons are pressed. */
for (btn = 1; btn <= 11 && !(buttons & (1<<(btn-1))); btn++)
;
code = 32;
} else {
if (!IS_SET(MODE_MOUSESGR) && e->xbutton.type == ButtonRelease) {
button = 3;
} else {
button -= Button1;
if (button >= 7)
button += 128 - 7;
else if (button >= 3)
button += 64 - 3;
}
if (e->xbutton.type == ButtonPress) {
oldbutton = button;
ox = x;
oy = y;
} else if (e->xbutton.type == ButtonRelease) {
oldbutton = 3;
btn = e->xbutton.button;
/* Only buttons 1 through 11 can be encoded */
if (btn < 1 || btn > 11)
return;
if (e->type == ButtonRelease) {
/* MODE_MOUSEX10: no button release reporting */
if (IS_SET(MODE_MOUSEX10))
return;
if (button == 64 || button == 65)
/* Don't send release events for the scroll wheel */
if (btn == 4 || btn == 5)
return;
}
code = 0;
}
ox = x;
oy = y;
/* Encode btn into code. If no button is pressed for a motion event in
* MODE_MOUSEMANY, then encode it as a release. */
if ((!IS_SET(MODE_MOUSESGR) && e->type == ButtonRelease) || btn == 12)
code += 3;
else if (btn >= 8)
code += 128 + btn - 8;
else if (btn >= 4)
code += 64 + btn - 4;
else
code += btn - 1;
if (!IS_SET(MODE_MOUSEX10)) {
button += ((state & ShiftMask ) ? 4 : 0)
+ ((state & Mod4Mask ) ? 8 : 0)
+ ((state & ControlMask) ? 16 : 0);
code += ((state & ShiftMask ) ? 4 : 0)
+ ((state & Mod1Mask ) ? 8 : 0) /* meta key: alt */
+ ((state & ControlMask) ? 16 : 0);
}
if (IS_SET(MODE_MOUSESGR)) {
len = snprintf(buf, sizeof(buf), "\033[<%d;%d;%d%c",
button, x+1, y+1,
e->xbutton.type == ButtonRelease ? 'm' : 'M');
code, x+1, y+1,
e->type == ButtonRelease ? 'm' : 'M');
} else if (x < 223 && y < 223) {
len = snprintf(buf, sizeof(buf), "\033[M%c%c%c",
32+button, 32+x+1, 32+y+1);
32+code, 32+x+1, 32+y+1);
} else {
return;
}
@ -461,9 +468,13 @@ mouseaction(XEvent *e, uint release)
void
bpress(XEvent *e)
{
int btn = e->xbutton.button;
struct timespec now;
int snap;
if (1 <= btn && btn <= 11)
buttons |= 1 << (btn-1);
if (IS_SET(MODE_MOUSE) && !(e->xbutton.state & forcemousemod)) {
mousereport(e);
return;
@ -472,7 +483,7 @@ bpress(XEvent *e)
if (mouseaction(e, 0))
return;
if (e->xbutton.button == Button1) {
if (btn == Button1) {
/*
* If the user clicks below predefined timeouts specific
* snapping behaviour is exposed.
@ -686,6 +697,11 @@ xsetsel(char *str)
void
brelease(XEvent *e)
{
int btn = e->xbutton.button;
if (1 <= btn && btn <= 11)
buttons &= ~(1 << (btn-1));
if (IS_SET(MODE_MOUSE) && !(e->xbutton.state & forcemousemod)) {
mousereport(e);
return;
@ -693,7 +709,7 @@ brelease(XEvent *e)
if (mouseaction(e, 1))
return;
if (e->xbutton.button == Button1)
if (btn == Button1)
mousesel(e, 1);
}
@ -799,12 +815,25 @@ xloadcols(void)
loaded = 1;
}
int
xgetcolor(int x, unsigned char *r, unsigned char *g, unsigned char *b)
{
if (!BETWEEN(x, 0, dc.collen - 1))
return 1;
*r = dc.col[x].color.red >> 8;
*g = dc.col[x].color.green >> 8;
*b = dc.col[x].color.blue >> 8;
return 0;
}
int
xsetcolorname(int x, const char *name)
{
Color ncolor;
if (!BETWEEN(x, 0, dc.collen))
if (!BETWEEN(x, 0, dc.collen - 1))
return 1;
if (!xloadcolor(x, name, &ncolor))
@ -952,7 +981,7 @@ xloadfont(Font *f, FcPattern *pattern)
}
void
xloadfonts(char *fontstr, double fontsize)
xloadfonts(const char *fontstr, double fontsize)
{
FcPattern *pattern;
double fontval;
@ -960,7 +989,7 @@ xloadfonts(char *fontstr, double fontsize)
if (fontstr[0] == '-')
pattern = XftXlfdParse(fontstr, False, False);
else
pattern = FcNameParse((FcChar8 *)fontstr);
pattern = FcNameParse((const FcChar8 *)fontstr);
if (!pattern)
die("can't open font %s\n", fontstr);
@ -1102,7 +1131,7 @@ xinit(int cols, int rows)
{
XGCValues gcvalues;
Cursor cursor;
Window parent;
Window parent, root;
pid_t thispid = getpid();
XColor xmousefg, xmousebg;
@ -1139,16 +1168,19 @@ xinit(int cols, int rows)
| ButtonMotionMask | ButtonPressMask | ButtonReleaseMask;
xw.attrs.colormap = xw.cmap;
root = XRootWindow(xw.dpy, xw.scr);
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,
parent = root;
xw.win = XCreateWindow(xw.dpy, root, xw.l, xw.t,
win.w, win.h, 0, XDefaultDepth(xw.dpy, xw.scr), InputOutput,
xw.vis, CWBackPixel | CWBorderPixel | CWBitGravity
| CWEventMask | CWColormap, &xw.attrs);
if (parent != root)
XReparentWindow(xw.dpy, xw.win, parent, xw.l, xw.t);
memset(&gcvalues, 0, sizeof(gcvalues));
gcvalues.graphics_exposures = False;
dc.gc = XCreateGC(xw.dpy, parent, GCGraphicsExposures,
dc.gc = XCreateGC(xw.dpy, xw.win, GCGraphicsExposures,
&gcvalues);
xw.buf = XCreatePixmap(xw.dpy, xw.win, win.w, win.h,
DefaultDepth(xw.dpy, xw.scr));
@ -1464,12 +1496,12 @@ xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, i
/* Render underline and strikethrough. */
if (base.mode & ATTR_UNDERLINE) {
XftDrawRect(xw.draw, fg, winx, winy + dc.font.ascent + 1,
XftDrawRect(xw.draw, fg, winx, winy + dc.font.ascent * chscale + 1,
width, 1);
}
if (base.mode & ATTR_STRUCK) {
XftDrawRect(xw.draw, fg, winx, winy + 2 * dc.font.ascent / 3,
XftDrawRect(xw.draw, fg, winx, winy + 2 * dc.font.ascent * chscale / 3,
width, 1);
}
@ -1588,8 +1620,12 @@ xseticontitle(char *p)
XTextProperty prop;
DEFAULT(p, opt_title);
Xutf8TextListToTextProperty(xw.dpy, &p, 1, XUTF8StringStyle,
&prop);
if (p[0] == '\0')
p = opt_title;
if (Xutf8TextListToTextProperty(xw.dpy, &p, 1, XUTF8StringStyle,
&prop) != Success)
return;
XSetWMIconName(xw.dpy, xw.win, &prop);
XSetTextProperty(xw.dpy, xw.win, &prop, xw.netwmiconname);
XFree(prop.value);
@ -1601,8 +1637,12 @@ xsettitle(char *p)
XTextProperty prop;
DEFAULT(p, opt_title);
Xutf8TextListToTextProperty(xw.dpy, &p, 1, XUTF8StringStyle,
&prop);
if (p[0] == '\0')
p = opt_title;
if (Xutf8TextListToTextProperty(xw.dpy, &p, 1, XUTF8StringStyle,
&prop) != Success)
return;
XSetWMName(xw.dpy, xw.win, &prop);
XSetTextProperty(xw.dpy, xw.win, &prop, xw.netwmname);
XFree(prop.value);
@ -1802,7 +1842,7 @@ void
kpress(XEvent *ev)
{
XKeyEvent *e = &ev->xkey;
KeySym ksym;
KeySym ksym = NoSymbol;
char buf[64], *customkey;
int len;
Rune c;
@ -1812,10 +1852,13 @@ kpress(XEvent *ev)
if (IS_SET(MODE_KBDLOCK))
return;
if (xw.ime.xic)
if (xw.ime.xic) {
len = XmbLookupString(xw.ime.xic, e, buf, sizeof buf, &ksym, &status);
else
if (status == XBufferOverflow)
return;
} else {
len = XLookupString(e, buf, sizeof buf, &ksym, NULL);
}
/* 1. shortcuts */
for (bp = shortcuts; bp < shortcuts + LEN(shortcuts); bp++) {
if (ksym == bp->keysym && match(bp->mod, e->state)) {


Loading…
Cancel
Save