diff options
| author | trainytrain <trainytrain@rape.lol> | 2021-05-09 01:53:29 -0700 |
|---|---|---|
| committer | trainytrain <trainytrain@rape.lol> | 2021-05-09 01:53:29 -0700 |
| commit | 64ad31237da6d14f0193adb7f1210255d5d647dd (patch) | |
| tree | 3a6f8bcacd6a0211fd3dd0b8b7ae42df0539883d | |
| parent | 7e6e779130327e065fcf587afa80f13150d0de31 (diff) | |
init
| -rw-r--r-- | FUNDING.yml | 2 | ||||
| -rw-r--r-- | LICENSE | 2 | ||||
| -rw-r--r-- | Makefile | 9 | ||||
| -rw-r--r-- | PKGBUILD | 2 | ||||
| -rw-r--r-- | README.md | 58 | ||||
| -rw-r--r-- | Xdefaults | 127 | ||||
| -rw-r--r-- | config.h | 89 | ||||
| -rw-r--r-- | config.mk | 12 | ||||
| -rwxr-xr-x | st-urlhandler | 20 | ||||
| -rw-r--r-- | st.1 | 10 | ||||
| -rw-r--r-- | st.c | 333 | ||||
| -rw-r--r-- | st.h | 25 | ||||
| -rw-r--r-- | st.info | 33 | ||||
| -rw-r--r-- | win.h | 2 | ||||
| -rw-r--r-- | x.c | 417 |
15 files changed, 490 insertions, 651 deletions
diff --git a/FUNDING.yml b/FUNDING.yml deleted file mode 100644 index c7c9a22..0000000 --- a/FUNDING.yml +++ /dev/null @@ -1,2 +0,0 @@ -custom: ["https://lukesmith.xyz/donate.html"] -github: lukesmithxyz @@ -1,6 +1,6 @@ MIT/X Consortium License -© 2014-2020 Hiltjo Posthuma <hiltjo at codemadness dot org> +© 2014-2018 Hiltjo Posthuma <hiltjo at codemadness dot org> © 2018 Devin J. Pohly <djpohly at gmail dot com> © 2014-2017 Quentin Rameau <quinq at fifth dot space> © 2009-2012 Aurélien APTEL <aurelien dot aptel at gmail dot com> @@ -15,6 +15,9 @@ options: @echo "LDFLAGS = $(STLDFLAGS)" @echo "CC = $(CC)" +config.h: + cp config.def.h config.h + .c.o: $(CC) $(STCFLAGS) -c $< @@ -29,19 +32,17 @@ st: $(OBJ) $(CC) -o $@ $(OBJ) $(STLDFLAGS) clean: - rm -f st $(OBJ) st-$(VERSION).tar.gz *.rej *.orig *.o + rm -f st $(OBJ) st-$(VERSION).tar.gz *.o *.orig *.rej dist: clean mkdir -p st-$(VERSION) cp -R FAQ LEGACY TODO LICENSE Makefile README config.mk\ - config.h st.info st.1 arg.h st.h win.h $(SRC)\ + config.def.h st.info st.1 arg.h st.h win.h $(SRC)\ st-$(VERSION) tar -cf - st-$(VERSION) | gzip > st-$(VERSION).tar.gz rm -rf st-$(VERSION) install: st - git submodule init - git submodule update mkdir -p $(DESTDIR)$(PREFIX)/bin cp -f st $(DESTDIR)$(PREFIX)/bin cp -f st-copyout $(DESTDIR)$(PREFIX)/bin @@ -41,5 +41,5 @@ package() { make PREFIX=/usr DESTDIR="${pkgdir}" install install -Dm644 LICENSE "${pkgdir}/usr/share/licenses/${pkgname}/LICENSE" install -Dm644 README.md "${pkgdir}/usr/share/doc/${pkgname}/README.md" - install -Dm644 Xdefaults "${pkgdir}/usr/share/doc/${pkgname}/Xdefaults.example" + install -Dm644 .Xdefaults "${pkgdir}/usr/share/doc/${pkgname}/Xdefaults.example" } @@ -1,7 +1,7 @@ -# Luke's build of st - the simple (suckless) terminal +# Tyler's build of st - the simple (suckless) terminal +This is basically the same thing as Luke Smith's [st build](https://github.com/LukeSmithxyz/st) with some settings that work better for me -The [suckless terminal (st)](https://st.suckless.org/) with some additional -features that make it literally the best terminal emulator ever: +The [suckless terminal (st)](https://st.suckless.org/) with some additional features that make it literally the best terminal emulator ever: ## Unique features (using dmenu) @@ -11,12 +11,9 @@ features that make it literally the best terminal emulator ever: ## Bindings for -+ scroll with `alt-↑/↓` or `alt-pageup/down` or `shift` while scrolling the - mouse (via [scroll](https://github.com/lukesmithxyz/scroll)). -+ OR **vim-bindings**: scroll up/down in history with `alt-k` and `alt-j`. - Faster with `alt-u`/`alt-d`. -+ **zoom/change font size**: same bindings as above, but holding down shift as - well. `alt-home` returns to default ++ **scrollback** with `alt-↑/↓` or `alt-pageup/down` or `shift` while scrolling the mouse ++ OR **vim-bindings**: scroll up/down in history with `alt-k` and `alt-j`. Faster with `alt-u`/`alt-d`. ++ **zoom/change font size**: same bindings as above, but holding down shift as well. `alt-home` returns to default + **copy text** with `alt-c`, **paste** is `alt-v` or `shift-insert` ## Pretty stuff @@ -24,48 +21,34 @@ features that make it literally the best terminal emulator ever: + Compatibility with `Xresources` and `pywal` for dynamic colors. + Default [gruvbox](https://github.com/morhetz/gruvbox) colors otherwise. + Transparency/alpha, which is also adjustable from your `Xresources`. -+ Default font is system "mono" at 14pt, meaning the font will match your - system font. ++ Default font is system "mono" at 14pt, meaning the font will match your system font. ## Other st patches -+ Boxdraw -+ Ligatures ++ Vertcenter ++ Scrollback + font2 -+ updated to latest version 0.8.4 ++ updated to latest version 0.8.2 ## Installation for newbs -You should have xlib header files and libharfbuzz build files installed. - ``` git clone https://github.com/LukeSmithxyz/st cd st sudo make install ``` -Note that [scroll](https://github.com/lukesmithxyz/scroll) is automatically -pulled and installed when you make this build of st. - -Users of Arch-based distros can also install it from the AUR as -[st-luke-git](https://aur.archlinux.org/packages/st-luke-git/). +Users of Arch-based distros can also install it from the AUR as [st-luke-git](https://aur.archlinux.org/packages/st-luke-git/). -Obviously, `make` is required to build. `fontconfig` is required for the -default build, since it asks `fontconfig` for your system monospace font. It -might be obvious, but `libX11` and `libXft` are required as well. Chances are, -you have all of this installed already. +Obviously, `make` is required to build. `fontconfig` is required for the default build, since it asks `fontconfig` for your system monospace font. It might be obvious, but `libX11` and `libXft` are required as well. Chances are, you have all of this installed already. -On OpenBSD, be sure to edit `config.mk` first and remove `-lrt` from the -`$LIBS` before compiling. +On OpenBSD, be sure to edit `config.mk` first and remove `-lrt` from the `$LIBS` before compiling. -Be sure to have a composite manager (`xcompmgr`, `picom`, etc.) running if you -want transparency. +Be sure to have a composite manager (`xcompmgr`, `picom`, etc.) running if you want transparency. ## How to configure dynamically with Xresources -For many key variables, this build of `st` will look for X settings set in -either `~/.Xdefaults` or `~/.Xresources`. You must run `xrdb` on one of these -files to load the settings. +For many key variables, this build of `st` will look for X settings set in either `~/.Xdefaults` or `~/.Xresources`. You must run `xrdb` on one of these files to load the settings. For example, you can define your desired fonts, transparency or colors: @@ -76,8 +59,7 @@ For example, you can define your desired fonts, transparency or colors: ... ``` -The `alpha` value (for transparency) goes from `0` (transparent) to `1` -(opaque). There is an example `Xdefaults` file in this respository. +The `alpha` value (for transparency) goes from `0` (transparent) to `1` (opaque). ### Colors @@ -91,13 +73,9 @@ Note that when you run `wal`, it will negate the transparency of existing window ## Notes on Emojis and Special Characters -If st crashes when viewing emojis, install -[libxft-bgra](https://aur.archlinux.org/packages/libxft-bgra/) from the AUR. +If st crashes when viewing emojis, install [libxft-bgra](https://aur.archlinux.org/packages/libxft-bgra/) from the AUR. -Note that some special characters may appear truncated if too wide. You might -want to manually set your prefered emoji/special character font to a lower size -in the `config.h` file to avoid this. By default, JoyPixels is used at a -smaller size than the usual text. +Note that some special characters may appear truncated if too wide. You might want to manually set your prefered emoji/special character font to a lower size in the `config.h` file to avoid this. By default, JoyPixels is used at a smaller size than the usual text. ## Contact diff --git a/Xdefaults b/Xdefaults deleted file mode 100644 index 704f2db..0000000 --- a/Xdefaults +++ /dev/null @@ -1,127 +0,0 @@ -!! Transparency (0-1): -st.alpha: 0.92 - -!! Set a default font and font size as below: -st.font: Monospace-11; - -! st.termname: st-256color -! st.borderpx: 2 - -!! Set the background, foreground and cursor colors as below: - -!! gruvbox: -*.color0: #1d2021 -*.color1: #cc241d -*.color2: #98971a -*.color3: #d79921 -*.color4: #458588 -*.color5: #b16286 -*.color6: #689d6a -*.color7: #a89984 -*.color8: #928374 -*.color9: #fb4934 -*.color10: #b8bb26 -*.color11: #fabd2f -*.color12: #83a598 -*.color13: #d3869b -*.color14: #8ec07c -*.color15: #ebdbb2 -*.background: #282828 -*.foreground: white -*.cursorColor: white - -/* /1* !! gruvbox light: *1/ */ -/* *.color0: #fbf1c7 */ -/* *.color1: #cc241d */ -/* *.color2: #98971a */ -/* *.color3: #d79921 */ -/* *.color4: #458588 */ -/* *.color5: #b16286 */ -/* *.color6: #689d6a */ -/* *.color7: #7c6f64 */ -/* *.color8: #928374 */ -/* *.color9: #9d0006 */ -/* *.color10: #79740e */ -/* *.color11: #b57614 */ -/* *.color12: #076678 */ -/* *.color13: #8f3f71 */ -/* *.color14: #427b58 */ -/* *.color15: #3c3836 */ -/* *.background: #fbf1c7 */ -/* *.foreground: #282828 */ -/* *.cursorColor: #282828 */ - -/* !! brogrammer: */ -/* *.foreground: #d6dbe5 */ -/* *.background: #131313 */ -/* *.color0: #1f1f1f */ -/* *.color8: #d6dbe5 */ -/* *.color1: #f81118 */ -/* *.color9: #de352e */ -/* *.color2: #2dc55e */ -/* *.color10: #1dd361 */ -/* *.color3: #ecba0f */ -/* *.color11: #f3bd09 */ -/* *.color4: #2a84d2 */ -/* *.color12: #1081d6 */ -/* *.color5: #4e5ab7 */ -/* *.color13: #5350b9 */ -/* *.color6: #1081d6 */ -/* *.color14: #0f7ddb */ -/* *.color7: #d6dbe5 */ -/* *.color15: #ffffff */ -/* *.colorBD: #d6dbe5 */ - -/* ! base16 */ -/* *.color0: #181818 */ -/* *.color1: #ab4642 */ -/* *.color2: #a1b56c */ -/* *.color3: #f7ca88 */ -/* *.color4: #7cafc2 */ -/* *.color5: #ba8baf */ -/* *.color6: #86c1b9 */ -/* *.color7: #d8d8d8 */ -/* *.color8: #585858 */ -/* *.color9: #ab4642 */ -/* *.color10: #a1b56c */ -/* *.color11: #f7ca88 */ -/* *.color12: #7cafc2 */ -/* *.color13: #ba8baf */ -/* *.color14: #86c1b9 */ -/* *.color15: #f8f8f8 */ - -/* !! solarized */ -/* *.color0: #073642 */ -/* *.color1: #dc322f */ -/* *.color2: #859900 */ -/* *.color3: #b58900 */ -/* *.color4: #268bd2 */ -/* *.color5: #d33682 */ -/* *.color6: #2aa198 */ -/* *.color7: #eee8d5 */ -/* *.color9: #cb4b16 */ -/* *.color8: #fdf6e3 */ -/* *.color10: #586e75 */ -/* *.color11: #657b83 */ -/* *.color12: #839496 */ -/* *.color13: #6c71c4 */ -/* *.color14: #93a1a1 */ -/* *.color15: #fdf6e3 */ - -/* !! xterm */ -/* *.color0: #000000 */ -/* *.color1: #cd0000 */ -/* *.color2: #00cd00 */ -/* *.color3: #cdcd00 */ -/* *.color4: #0000cd */ -/* *.color5: #cd00cd */ -/* *.color6: #00cdcd */ -/* *.color7: #e5e5e5 */ -/* *.color8: #4d4d4d */ -/* *.color9: #ff0000 */ -/* *.color10: #00ff00 */ -/* *.color11: #ffff00 */ -/* *.color12: #0000ff */ -/* *.color13: #ff00ff */ -/* *.color14: #00ffff */ -/* *.color15: #aabac8 */ @@ -5,22 +5,20 @@ * * font: see http://freedesktop.org/software/fontconfig/fontconfig-user.html */ -static char *font = "mono:pixelsize=12:antialias=true:autohint=true"; -static char *font2[] = { "JoyPixels:pixelsize=10:antialias=true:autohint=true" }; -static int borderpx = 2; +static char *font = "JetBrainsMonoMedium Nerd Font:pixelsize=16:antialias=true:autohint=true"; +static char *font2[] = { "Noto Color Emoji:pixelsize=10:antialias=true:autohint=true" }; +static int borderpx = 10; /* * What program is execed by st depends of these precedence rules: * 1: program passed with -e - * 2: scroll and/or utmp + * 2: utmp option * 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 */ @@ -44,10 +42,6 @@ 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 @@ -64,6 +58,13 @@ static double maxlatency = 33; static unsigned int blinktimeout = 800; /* + * interval (in milliseconds) between each successive call to ximspot. This + * improves terminal performance while not reducing functionality to those + * whom need XIM support. + */ +int ximspot_update_interval = 1000; + +/* * thickness of underline and bar cursors */ static unsigned int cursorthickness = 2; @@ -75,10 +76,10 @@ static unsigned int cursorthickness = 2; * 0: disable (render all U25XX glyphs normally from the font). */ const int boxdraw = 1; -const int boxdraw_bold = 0; +const int boxdraw_bold = 1; /* braille (U28XX): 1: render as adjacent "pixels", 0: use font */ -const int boxdraw_braille = 0; +const int boxdraw_braille = 1; /* * bell volume. It must be a value between -100 and 100. Use 0 for disabling @@ -87,7 +88,7 @@ const int boxdraw_braille = 0; static int bellvolume = 0; /* default TERM value */ -char *termname = "st-256color"; +char *termname = "xterm-256color"; /* * spaces per tab @@ -107,7 +108,7 @@ char *termname = "st-256color"; unsigned int tabspaces = 8; /* bg opacity */ -float alpha = 0.8; +float alpha = 0.95; /* Terminal colors (16 first used in escape sequence) */ static const char *colorname[] = { @@ -152,7 +153,7 @@ unsigned int defaultrcs = 257; * 6: Bar ("|") * 7: Snowman ("☃") */ -static unsigned int cursorshape = 2; +static unsigned int cursorshape = 4; /* * Default columns and rows numbers @@ -175,13 +176,6 @@ static unsigned int mousebg = 0; 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; - -/* * Xresources preferences to load at startup */ ResourcePref resources[] = { @@ -208,8 +202,6 @@ ResourcePref resources[] = { { "cursorColor", STRING, &colorname[256] }, { "termname", STRING, &termname }, { "shell", STRING, &shell }, - { "minlatency", INTEGER, &minlatency }, - { "maxlatency", INTEGER, &maxlatency }, { "blinktimeout", INTEGER, &blinktimeout }, { "bellvolume", INTEGER, &bellvolume }, { "tabspaces", INTEGER, &tabspaces }, @@ -217,6 +209,7 @@ ResourcePref resources[] = { { "cwscale", FLOAT, &cwscale }, { "chscale", FLOAT, &chscale }, { "alpha", FLOAT, &alpha }, + { "ximspot_update_interval", INTEGER, &ximspot_update_interval }, }; /* @@ -224,24 +217,30 @@ ResourcePref resources[] = { * Beware that overloading Button1 will disable the selection. */ static MouseShortcut mshortcuts[] = { - /* mask button function argument release */ - { XK_NO_MOD, Button4, kscrollup, {.i = 1} }, - { XK_NO_MOD, Button5, kscrolldown, {.i = 1} }, - { 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"} }, + /* button mask string */ + { Button4, XK_NO_MOD, "\031" }, + { Button5, XK_NO_MOD, "\005" }, }; /* Internal keyboard shortcuts. */ #define MODKEY Mod1Mask #define TERMMOD (Mod1Mask|ShiftMask) -static char *openurlcmd[] = { "/bin/sh", "-c", "st-urlhandler -o", "externalpipe", NULL }; -static char *copyurlcmd[] = { "/bin/sh", "-c", "st-urlhandler -c", "externalpipe", NULL }; -static char *copyoutput[] = { "/bin/sh", "-c", "st-copyout", "externalpipe", NULL }; +MouseKey mkeys[] = { + /* button mask function argument */ + { Button4, XK_NO_MOD, kscrollup, {.i = 1} }, + { Button5, XK_NO_MOD, kscrolldown, {.i = 1} }, + { Button4, TERMMOD, zoom, {.f = +1} }, + { Button5, TERMMOD, zoom, {.f = -1} }, +}; + +static char *openurlcmd[] = { "/bin/sh", "-c", "st-urlhandler", "externalpipe", NULL }; +static char *copyurlcmd[] = { "/bin/sh", "-c", + "tmp=$(sed 's/.*│//g' | tr -d '\n' | grep -aEo '(((http|https|gopher|gemini|ftp|ftps|git)://|www\\.)[a-zA-Z0-9.]*[:]?[a-zA-Z0-9./@$&%?$#=_-~]*)|((magnet:\\?xt=urn:btih:)[a-zA-Z0-9]*)' | uniq | sed 's/^www./http:\\/\\/www\\./g' ); IFS=; [ ! -z $tmp ] && echo $tmp | dmenu -i -p 'Copy which url?' -l 10 | tr -d '\n' | xclip -selection clipboard", + "externalpipe", NULL }; + +static char *copyoutput[] = { "/bin/sh", "-c", "st-copyout", "externalpipe", NULL }; static Shortcut shortcuts[] = { /* mask keysym function argument */ @@ -251,14 +250,13 @@ static Shortcut shortcuts[] = { { 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} }, + { MODKEY, XK_Home, zoomreset, {.f = 0} }, { MODKEY, XK_c, clipcopy, {.i = 0} }, { ShiftMask, XK_Insert, clippaste, {.i = 0} }, { MODKEY, XK_v, clippaste, {.i = 0} }, - { ShiftMask, XK_Insert, selpaste, {.i = 0} }, - { TERMMOD, XK_Num_Lock, numlock, {.i = 0} }, + { XK_ANY_MOD, Button2, selpaste, {.i = 0} }, + { MODKEY, XK_Num_Lock, numlock, {.i = 0} }, + { MODKEY, XK_Control_L, iso14755, {.i = 0} }, { ShiftMask, XK_Page_Up, kscrollup, {.i = -1} }, { ShiftMask, XK_Page_Down, kscrolldown, {.i = -1} }, { MODKEY, XK_Page_Up, kscrollup, {.i = -1} }, @@ -297,6 +295,10 @@ static Shortcut shortcuts[] = { * * 0: no value * * > 0: cursor application mode enabled * * < 0: cursor application mode disabled + * crlf value + * * 0: no value + * * > 0: crlf mode is enabled + * * < 0: crlf mode is disabled * * Be careful with the order of the definitions because st searches in * this table sequentially, so any XK_ANY_MOD must be in the last @@ -316,6 +318,13 @@ static KeySym mappedkeys[] = { -1 }; static uint ignoremod = Mod2Mask|XK_SWITCH_MOD; /* + * Override mouse-select while mask is active (when MODE_MOUSE is set). + * Note that if you want to use ShiftMask with selmasks, set this to an other + * modifier, set to 0 to not use it. + */ +static uint forceselmod = ShiftMask; + +/* * This is the huge key array which defines all compatibility to the Linux * world. Please decide about changes wisely. */ @@ -1,15 +1,19 @@ # st version -VERSION = 0.8.4 +VERSION = 0.8.2 # Customize below to fit your system # paths -PREFIX = /usr/local +PREFIX ?= /usr/local MANPREFIX = $(PREFIX)/share/man X11INC = /usr/X11R6/include X11LIB = /usr/X11R6/lib +# include X11 in Ubuntu +# X11INC = /usr/include/X11R6 +# X11LIB = /usr/lib/X11R6 + PKG_CONFIG = pkg-config # includes and libs @@ -30,8 +34,8 @@ 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` +# `pkg-config --libs fontconfig` \ +# `pkg-config --libs freetype2` # compiler and linker # CC = c99 diff --git a/st-urlhandler b/st-urlhandler index e2a62f4..0d39dd5 100755 --- a/st-urlhandler +++ b/st-urlhandler @@ -1,19 +1,15 @@ #!/bin/sh -urlregex="(((http|https|gopher|gemini|ftp|ftps|git)://|www\\.)[a-zA-Z0-9.]*[:]?[a-zA-Z0-9./@$&%?$\#=_~-]*)|((magnet:\\?xt=urn:btih:)[a-zA-Z0-9]*)" +urlregex="(((http|https)://|www\\.)[a-zA-Z0-9.]*[:]?[a-zA-Z0-9./@$&%?$\#=_~-]*)|((magnet:\\?xt=urn:btih:)[a-zA-Z0-9]*)" -urls="$(sed 's/.*│//g' | tr -d '\n' | # First remove linebreaks and mutt sidebars: +# First remove linebreaks and mutt sidebars: +urls="$(sed 's/.*│//g' | tr -d '\n' | grep -aEo "$urlregex" | # grep only urls as defined above. uniq | # Ignore neighboring duplicates. - sed "s/\(\.\|,\|;\|\!\\|\?\)$//; - s/^www./http:\/\/www\./")" # xdg-open will not detect url without http + sed 's/^www./http:\/\/www\./g')" -[ -z "$urls" ] && exit 1 +[ -z "$urls" ] && exit -while getopts "hoc" o; do case "${o}" in - h) printf "Optional arguments for custom use:\\n -c: copy\\n -o: xdg-open\\n -h: Show this message\\n" && exit 1 ;; - o) chosen="$(echo "$urls" | dmenu -i -p 'Follow which url?' -l 10)" - setsid xdg-open "$chosen" >/dev/null 2>&1 & ;; - c) echo "$urls" | dmenu -i -p 'Copy which url?' -l 10 | tr -d '\n' | xclip -selection clipboard ;; - *) printf "Invalid option: -%s\\n" "$OPTARG" && exit 1 ;; -esac done +chosen="$(echo "$urls" | dmenu -i -p 'Follow which url?' -l 10)" + +setsid xdg-open "$chosen" >/dev/null 2>&1 & @@ -1,6 +1,6 @@ .TH ST 1 st\-VERSION .SH NAME -st \- simple terminal +st \- simple terminal (Luke Smith (https://lukesmith.xyz)'s build) .SH SYNOPSIS .B st .RB [ \-aiv ] @@ -176,6 +176,10 @@ Print the full screen to the .B Print Screen Print the selection to the .I iofile. +.TP +.B Alt-Ctrl +Launch dmenu to enter a unicode codepoint and send the corresponding glyph +to st. .SH CUSTOMIZATION .B st can be customized by creating a custom config.h and (re)compiling the source @@ -187,7 +191,7 @@ See the LICENSE file for the terms of redistribution. .SH SEE ALSO .BR tabbed (1), .BR utmp (1), -.BR stty (1), -.BR scroll (1) +.BR stty (1) .SH BUGS See the TODO file in the distribution. + @@ -14,6 +14,7 @@ #include <sys/types.h> #include <sys/wait.h> #include <termios.h> +#include <time.h> #include <unistd.h> #include <wchar.h> @@ -39,15 +40,20 @@ /* macros */ #define IS_SET(flag) ((term.mode & (flag)) != 0) -#define ISCONTROLC0(c) (BETWEEN(c, 0, 0x1f) || (c) == 0x7f) +#define NUMMAXLEN(x) ((int)(sizeof(x) * 2.56 + 0.5) + 1) +#define ISCONTROLC0(c) (BETWEEN(c, 0, 0x1f) || (c) == '\177') #define ISCONTROLC1(c) (BETWEEN(c, 0x80, 0x9f)) #define ISCONTROL(c) (ISCONTROLC0(c) || ISCONTROLC1(c)) #define ISDELIM(u) (u && wcschr(worddelimiters, u)) #define TLINE(y) ((y) < term.scr ? term.hist[((y) + term.histi - \ term.scr + HISTSIZE + 1) % HISTSIZE] : \ term.line[(y) - term.scr]) + #define TLINE_HIST(y) ((y) <= HISTSIZE-term.row+2 ? term.hist[(y)] : term.line[(y-HISTSIZE+term.row-3)]) +/* constants */ +#define ISO14755CMD "dmenu -w \"$WINDOWID\" -p codepoint: </dev/null" + enum term_mode { MODE_WRAP = 1 << 0, MODE_INSERT = 1 << 1, @@ -56,6 +62,7 @@ enum term_mode { MODE_ECHO = 1 << 4, MODE_PRINT = 1 << 5, MODE_UTF8 = 1 << 6, + MODE_SIXEL = 1 << 7, }; enum cursor_movement { @@ -82,11 +89,12 @@ enum charset { enum escape_state { ESC_START = 1, ESC_CSI = 2, - ESC_STR = 4, /* DCS, OSC, PM, APC */ + ESC_STR = 4, /* OSC, PM, APC */ ESC_ALTCHARSET = 8, ESC_STR_END = 16, /* a final string was encountered */ ESC_TEST = 32, /* Enter in test mode */ ESC_UTF8 = 64, + ESC_DCS =128, }; typedef struct { @@ -135,14 +143,14 @@ typedef struct { int charset; /* current charset */ int icharset; /* selected charset for sequence */ int *tabs; - Rune lastc; /* last printed char outside of sequence, 0 if control */ + struct timespec last_ximspot_update; } Term; /* CSI Escape sequence structs */ /* ESC '[' [[ [<priv>] <arg> [;]] <mode> [<mode>]] */ typedef struct { char buf[ESC_BUF_SIZ]; /* raw string */ - size_t len; /* raw string length */ + int len; /* raw string length */ char priv; int arg[ESC_ARG_SIZ]; int narg; /* nb of args */ @@ -153,9 +161,8 @@ typedef struct { /* ESC type [[ [<priv>] <arg> [;]] <mode>] ESC '\' */ typedef struct { char type; /* ESC type ... */ - char *buf; /* allocated raw string */ - size_t siz; /* allocation size */ - size_t len; /* raw string length */ + char buf[STR_BUF_SIZ]; /* raw string */ + int len; /* raw string length */ char *args[STR_ARG_SIZ]; int narg; /* nb of args */ } STREscape; @@ -373,9 +380,8 @@ static const char base64_digits[] = { char base64dec_getc(const char **src) { - while (**src && !isprint(**src)) - (*src)++; - return **src ? *((*src)++) : '='; /* emulate padding if string ends */ + while (**src && !isprint(**src)) (*src)++; + return *((*src)++); } char * @@ -393,10 +399,6 @@ base64dec(const char *src) int c = base64_digits[(unsigned char) base64dec_getc(&src)]; int d = base64_digits[(unsigned char) base64dec_getc(&src)]; - /* invalid input. 'a' can be -1, e.g. if src is "\n" (c-str) */ - if (a == -1 || b == -1) - break; - *dst++ = (a << 2) | ((b & 0x30) >> 4); if (c == -1) break; @@ -655,8 +657,7 @@ getsel(void) * st. * FIXME: Fix the computer world. */ - if ((y < sel.ne.y || lastx >= linelen) && - (!(last->mode & ATTR_WRAP) || sel.type == SEL_RECTANGULAR)) + if ((y < sel.ne.y || lastx >= linelen) && !(last->mode & ATTR_WRAP)) *ptr++ = '\n'; } *ptr = 0; @@ -687,7 +688,7 @@ die(const char *errstr, ...) void execsh(char *cmd, char **args) { - char *sh, *prog, *arg; + char *sh, *prog; const struct passwd *pw; errno = 0; @@ -701,20 +702,13 @@ execsh(char *cmd, char **args) if ((sh = getenv("SHELL")) == NULL) sh = (pw->pw_shell[0]) ? pw->pw_shell : cmd; - if (args) { + if (args) prog = args[0]; - arg = NULL; - } else if (scroll) { - prog = scroll; - arg = utmp ? utmp : sh; - } else if (utmp) { + else if (utmp) prog = utmp; - arg = NULL; - } else { + else prog = sh; - arg = NULL; - } - DEFAULT(args, ((char *[]) {prog, arg, NULL})); + DEFAULT(args, ((char *[]) {prog, NULL})); unsetenv("COLUMNS"); unsetenv("LINES"); @@ -752,7 +746,7 @@ sigchld(int a) 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); + exit(0); } void @@ -845,25 +839,21 @@ ttyread(void) { static char buf[BUFSIZ]; static int buflen = 0; - int ret, written; + int written; + int ret; /* append read bytes to unprocessed bytes */ - ret = read(cmdfd, buf+buflen, LEN(buf)-buflen); - - switch (ret) { - case 0: - exit(0); - case -1: + if ((ret = read(cmdfd, buf+buflen, LEN(buf)-buflen)) < 0) die("couldn't read from shell: %s\n", strerror(errno)); - default: - buflen += ret; - written = twrite(buf, buflen, 0); - buflen -= written; - /* keep any incomplete UTF-8 byte sequence for the next call */ - if (buflen > 0) - memmove(buf, buf + written, buflen); - return ret; - } + buflen += ret; + + written = twrite(buf, buflen, 0); + buflen -= written; + /* keep any uncomplete utf8 char for the next call */ + if (buflen > 0) + memmove(buf, buf + written, buflen); + + return ret; } void @@ -1068,10 +1058,16 @@ void tnew(int col, int row) { term = (Term){ .c = { .attr = { .fg = defaultfg, .bg = defaultbg } } }; + clock_gettime(CLOCK_MONOTONIC, &term.last_ximspot_update); tresize(col, row); treset(); } +int tisaltscr(void) +{ + return IS_SET(MODE_ALTSCREEN); +} + void tswapscreen(void) { @@ -1140,8 +1136,7 @@ tscrolldown(int orig, int n, int copyhist) term.line[i-n] = temp; } - if (term.scr == 0) - selscroll(orig, n); + selscroll(orig, n); } void @@ -1171,8 +1166,7 @@ tscrollup(int orig, int n, int copyhist) term.line[i+n] = temp; } - if (term.scr == 0) - selscroll(orig, -n); + selscroll(orig, -n); } void @@ -1181,17 +1175,27 @@ selscroll(int orig, int n) if (sel.ob.x == -1) return; - if (BETWEEN(sel.nb.y, orig, term.bot) != BETWEEN(sel.ne.y, orig, term.bot)) { - selclear(); - } else if (BETWEEN(sel.nb.y, orig, term.bot)) { - sel.ob.y += n; - sel.oe.y += n; - if (sel.ob.y < term.top || sel.ob.y > term.bot || - sel.oe.y < term.top || sel.oe.y > term.bot) { + 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(); + return; + } + if (sel.type == SEL_RECTANGULAR) { + if (sel.ob.y < term.top) + sel.ob.y = term.top; + if (sel.oe.y > term.bot) + sel.oe.y = term.bot; } else { - selnormalize(); + if (sel.ob.y < term.top) { + sel.ob.y = term.top; + sel.ob.x = 0; + } + if (sel.oe.y > term.bot) { + sel.oe.y = term.bot; + sel.oe.x = term.col; + } } + selnormalize(); } } @@ -1726,12 +1730,6 @@ csihandle(void) if (csiescseq.arg[0] == 0) ttywrite(vtiden, strlen(vtiden), 0); break; - case 'b': /* REP -- if last char is printable print it <n> more times */ - DEFAULT(csiescseq.arg[0], 1); - if (term.lastc) - while (csiescseq.arg[0]-- > 0) - tputc(term.lastc); - break; case 'C': /* CUF -- Cursor <n> Forward */ case 'a': /* HPR -- Cursor <n> Forward */ DEFAULT(csiescseq.arg[0], 1); @@ -1855,7 +1853,7 @@ csihandle(void) break; case 'n': /* DSR – Device Status Report (cursor position) */ if (csiescseq.arg[0] == 6) { - len = snprintf(buf, sizeof(buf), "\033[%i;%iR", + len = snprintf(buf, sizeof(buf),"\033[%i;%iR", term.c.y+1, term.c.x+1); ttywrite(buf, len, 0); } @@ -1892,7 +1890,7 @@ csihandle(void) void csidump(void) { - size_t i; + int i; uint c; fprintf(stderr, "ESC["); @@ -1933,21 +1931,13 @@ strhandle(void) case ']': /* OSC -- Operating System Command */ switch (par) { case 0: - if (narg > 1) { - xsettitle(strescseq.args[1]); - xseticontitle(strescseq.args[1]); - } - return; case 1: - if (narg > 1) - xseticontitle(strescseq.args[1]); - return; case 2: if (narg > 1) xsettitle(strescseq.args[1]); return; case 52: - if (narg > 2 && allowwindowops) { + if (narg > 2) { dec = base64dec(strescseq.args[2]); if (dec) { xsetsel(dec); @@ -1958,22 +1948,35 @@ strhandle(void) } return; case 4: /* color set */ - if (narg < 3) + case 10: /* foreground set */ + case 11: /* background set */ + case 12: /* cursor color */ + if ((par == 4 && narg < 3) || narg < 2) break; - p = strescseq.args[2]; + p = strescseq.args[((par == 4) ? 2 : 1)]; /* FALLTHROUGH */ case 104: /* color reset, here p = NULL */ - j = (narg > 1) ? atoi(strescseq.args[1]) : -1; + if (par == 10) + j = defaultfg; + else if (par == 11) + j = defaultbg; + else if (par == 12) + j = defaultcs; + else + j = (narg > 1) ? atoi(strescseq.args[1]) : -1; + if (xsetcolorname(j, p)) { if (par == 104 && narg <= 1) return; /* color reset without parameter */ fprintf(stderr, "erresc: invalid color j=%d, p=%s\n", - j, p ? p : "(null)"); + j, p ? p : "(null)"); } else { /* * TODO if defaultbg color is changed, borders * are dirty */ + if (j == defaultbg) + xclearwin(); redraw(); } return; @@ -1983,6 +1986,7 @@ strhandle(void) xsettitle(strescseq.args[0]); return; case 'P': /* DCS -- Device Control String */ + term.mode |= ESC_DCS; case '_': /* APC -- Application Program Command */ case '^': /* PM -- Privacy Message */ return; @@ -2015,6 +2019,56 @@ strparse(void) } void +strdump(void) +{ + int i; + uint c; + + fprintf(stderr, "ESC%c", strescseq.type); + for (i = 0; i < strescseq.len; i++) { + c = strescseq.buf[i] & 0xff; + if (c == '\0') { + putc('\n', stderr); + return; + } else if (isprint(c)) { + putc(c, stderr); + } else if (c == '\n') { + fprintf(stderr, "(\\n)"); + } else if (c == '\r') { + fprintf(stderr, "(\\r)"); + } else if (c == 0x1b) { + fprintf(stderr, "(\\e)"); + } else { + fprintf(stderr, "(%02x)", c); + } + } + fprintf(stderr, "ESC\\\n"); +} + +void +strreset(void) +{ + memset(&strescseq, 0, sizeof(strescseq)); +} + +void +sendbreak(const Arg *arg) +{ + if (tcsendbreak(cmdfd, 0)) + perror("Error sending break"); +} + +void +tprinter(char *s, size_t len) +{ + if (iofd != -1 && xwrite(iofd, s, len) < 0) { + perror("Error writing to output file"); + close(iofd); + iofd = -1; + } +} + +void externalpipe(const Arg *arg) { int to[2]; @@ -2045,13 +2099,14 @@ externalpipe(const Arg *arg) /* ignore sigpipe for now, in case child exists early */ oldsigpipe = signal(SIGPIPE, SIG_IGN); newline = 0; + /* modify externalpipe patch to pipe history too */ for (n = 0; n <= HISTSIZE + 2; n++) { bp = TLINE_HIST(n); - lastpos = MIN(tlinehistlen(n) + 1, term.col) - 1; + lastpos = MIN(tlinehistlen(n) +1, term.col) - 1; if (lastpos < 0) break; - if (lastpos == 0) - continue; + if (lastpos == 0) + continue; end = &bp[lastpos + 1]; for (; bp < end; ++bp) if (xwrite(to[1], buf, utf8encode(bp->u, buf)) < 0) @@ -2070,56 +2125,25 @@ externalpipe(const Arg *arg) } void -strdump(void) +iso14755(const Arg *arg) { - size_t i; - uint c; + FILE *p; + char *us, *e, codepoint[9], uc[UTF_SIZ]; + unsigned long utf32; - fprintf(stderr, "ESC%c", strescseq.type); - for (i = 0; i < strescseq.len; i++) { - c = strescseq.buf[i] & 0xff; - if (c == '\0') { - putc('\n', stderr); - return; - } else if (isprint(c)) { - putc(c, stderr); - } else if (c == '\n') { - fprintf(stderr, "(\\n)"); - } else if (c == '\r') { - fprintf(stderr, "(\\r)"); - } else if (c == 0x1b) { - fprintf(stderr, "(\\e)"); - } else { - fprintf(stderr, "(%02x)", c); - } - } - fprintf(stderr, "ESC\\\n"); -} + if (!(p = popen(ISO14755CMD, "r"))) + return; -void -strreset(void) -{ - strescseq = (STREscape){ - .buf = xrealloc(strescseq.buf, STR_BUF_SIZ), - .siz = STR_BUF_SIZ, - }; -} + us = fgets(codepoint, sizeof(codepoint), p); + pclose(p); -void -sendbreak(const Arg *arg) -{ - if (tcsendbreak(cmdfd, 0)) - perror("Error sending break"); -} + if (!us || *us == '\0' || *us == '-' || strlen(us) > 7) + return; + if ((utf32 = strtoul(us, &e, 16)) == ULONG_MAX || + (*e != '\n' && *e != '\0')) + return; -void -tprinter(char *s, size_t len) -{ - if (iofd != -1 && xwrite(iofd, s, len) < 0) { - perror("Error writing to output file"); - close(iofd); - iofd = -1; - } + ttywrite(uc, utf8encode(utf32, uc), 1); } void @@ -2160,7 +2184,7 @@ tdumpline(int n) bp = &term.line[n][0]; end = &bp[MIN(tlinelen(n), term.col) - 1]; if (bp != end || bp->u != ' ') { - for ( ; bp <= end; ++bp) + for ( ;bp <= end; ++bp) tprinter(buf, utf8encode(bp->u, buf)); } tprinter("\n", 1); @@ -2231,9 +2255,12 @@ tdectest(char c) void tstrsequence(uchar c) { + strreset(); + switch (c) { case 0x90: /* DCS -- Device Control String */ c = 'P'; + term.esc |= ESC_DCS; break; case 0x9f: /* APC -- Application Program Command */ c = '_'; @@ -2245,7 +2272,6 @@ tstrsequence(uchar c) c = ']'; break; } - strreset(); strescseq.type = c; term.esc |= ESC_STR; } @@ -2288,7 +2314,6 @@ tcontrolcode(uchar ascii) return; case '\032': /* SUB */ tsetchar('?', &term.c.attr, term.c.x, term.c.y); - /* FALLTHROUGH */ case '\030': /* CAN */ csireset(); break; @@ -2443,13 +2468,15 @@ tputc(Rune u) Glyph *gp; control = ISCONTROL(u); - if (u < 127 || !IS_SET(MODE_UTF8)) { + if (!IS_SET(MODE_UTF8) && !IS_SET(MODE_SIXEL)) { c[0] = u; width = len = 1; } else { len = utf8encode(u, c); - if (!control && (width = wcwidth(u)) == -1) + if (!control && (width = wcwidth(u)) == -1) { + memcpy(c, "\357\277\275", 4); /* UTF_INVALID */ width = 1; + } } if (IS_SET(MODE_PRINT)) @@ -2464,12 +2491,24 @@ tputc(Rune u) if (term.esc & ESC_STR) { if (u == '\a' || u == 030 || u == 032 || u == 033 || ISCONTROLC1(u)) { - term.esc &= ~(ESC_START|ESC_STR); + term.esc &= ~(ESC_START|ESC_STR|ESC_DCS); + if (IS_SET(MODE_SIXEL)) { + /* TODO: render sixel */; + term.mode &= ~MODE_SIXEL; + return; + } term.esc |= ESC_STR_END; goto check_control_code; } - if (strescseq.len+len >= strescseq.siz) { + if (IS_SET(MODE_SIXEL)) { + /* TODO: implement sixel mode */ + return; + } + if (term.esc&ESC_DCS && strescseq.len == 0 && u == 'q') + term.mode |= MODE_SIXEL; + + if (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 @@ -2483,10 +2522,7 @@ tputc(Rune u) * term.esc = 0; * strhandle(); */ - if (strescseq.siz > (SIZE_MAX - UTF_SIZ) / 2) - return; - strescseq.siz *= 2; - strescseq.buf = xrealloc(strescseq.buf, strescseq.siz); + return; } memmove(&strescseq.buf[strescseq.len], c, len); @@ -2505,8 +2541,6 @@ check_control_code: /* * control codes are not shown ever */ - if (!term.esc) - term.lastc = 0; return; } else if (term.esc & ESC_START) { if (term.esc & ESC_CSI) { @@ -2537,7 +2571,7 @@ check_control_code: */ return; } - if (selected(term.c.x, term.c.y)) + if (sel.ob.x != -1 && BETWEEN(term.c.y, sel.ob.y, sel.oe.y)) selclear(); gp = &term.line[term.c.y][term.c.x]; @@ -2556,7 +2590,6 @@ check_control_code: } tsetchar(u, &term.c.attr, term.c.x, term.c.y); - term.lastc = u; if (width == 2) { gp->mode |= ATTR_WIDE; @@ -2580,7 +2613,7 @@ twrite(const char *buf, int buflen, int show_ctrl) int n; for (n = 0; n < buflen; n += charsize) { - if (IS_SET(MODE_UTF8)) { + if (IS_SET(MODE_UTF8) && !IS_SET(MODE_SIXEL)) { /* process a complete utf8 char */ charsize = utf8decode(buf + n, &u, buflen - n); if (charsize == 0) @@ -2704,7 +2737,6 @@ void drawregion(int x1, int y1, int x2, int y2) { int y; - for (y = y1; y < y2; y++) { if (!term.dirty[y]) continue; @@ -2717,7 +2749,7 @@ drawregion(int x1, int y1, int x2, int y2) void draw(void) { - int cx = term.c.x, ocx = term.ocx, ocy = term.ocy; + int cx = term.c.x; if (!xstartdraw()) return; @@ -2735,14 +2767,15 @@ draw(void) xdrawcursor(cx, term.c.y, term.line[term.c.y][cx], term.ocx, term.ocy, term.line[term.ocy][term.ocx], term.line[term.ocy], term.col); - /* xdrawcursor(cx, term.c.y, term.line[term.c.y][cx], */ - /* term.ocx, term.ocy, term.line[term.ocy][term.ocx], */ - /* term.line[term.ocy], term.col); */ - term.ocx = cx; - term.ocy = term.c.y; + term.ocx = cx, term.ocy = term.c.y; xfinishdraw(); - if (ocx != term.ocx || ocy != term.ocy) + + struct timespec now; + clock_gettime(CLOCK_MONOTONIC, &now); + if (ximspot_update_interval && TIMEDIFF(now, term.last_ximspot_update) > ximspot_update_interval) { xximspot(term.ocx, term.ocy); + term.last_ximspot_update = now; + } } void @@ -34,11 +34,17 @@ enum glyph_attribute { ATTR_WRAP = 1 << 8, ATTR_WIDE = 1 << 9, ATTR_WDUMMY = 1 << 10, - ATTR_BOXDRAW = 1 << 11, + ATTR_BOXDRAW = 1 << 11, ATTR_LIGA = 1 << 12, ATTR_BOLD_FAINT = ATTR_BOLD | ATTR_FAINT, }; +enum drawing_mode { + DRAW_NONE = 0, + DRAW_BG = 1 << 0, + DRAW_FG = 1 << 1, +}; + enum selection_mode { SEL_IDLE = 0, SEL_EMPTY = 1, @@ -77,14 +83,21 @@ typedef union { uint ui; float f; const void *v; - const char *s; } Arg; +typedef struct { + uint b; + uint mask; + void (*func)(const Arg *); + const Arg arg; +} MouseKey; + void die(const char *, ...); void redraw(void); void draw(void); void externalpipe(const Arg *); +void iso14755(const Arg *); void kscrolldown(const Arg *); void kscrollup(const Arg *); void printscreen(const Arg *); @@ -93,6 +106,7 @@ void sendbreak(const Arg *); void toggleprinter(const Arg *); int tattrset(int); +int tisaltscr(void); void tnew(int, int); void tresize(int, int); void tsetdirtattr(int); @@ -127,15 +141,16 @@ void drawboxes(int, int, int, int, XftColor *, XftColor *, const XftGlyphFontSpe /* config.h globals */ extern char *utmp; -extern char *scroll; extern char *stty_args; extern char *vtiden; extern wchar_t *worddelimiters; extern int allowaltscreen; -extern int allowwindowops; extern char *termname; extern unsigned int tabspaces; extern unsigned int defaultfg; extern unsigned int defaultbg; -extern float alpha; +extern unsigned int defaultcs; extern const int boxdraw, boxdraw_bold, boxdraw_braille; +extern float alpha; +extern MouseKey mkeys[]; +extern int ximspot_update_interval; @@ -1,4 +1,4 @@ -st-mono| simpleterm monocolor, +st| simpleterm, acsc=+C\,D-A.B0E``aaffgghFiGjjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~, am, bce, @@ -10,7 +10,7 @@ st-mono| simpleterm monocolor, civis=\E[?25l, clear=\E[H\E[2J, cnorm=\E[?12l\E[?25h, - colors#2, + colors#8, cols#80, cr=^M, csr=\E[%i%p1%d;%p2%dr, @@ -158,7 +158,6 @@ st-mono| simpleterm monocolor, rc=\E8, rev=\E[7m, ri=\EM, - rin=\E[%p1%dT, ritm=\E[23m, rmacs=\E(B, rmcup=\E[?1049l, @@ -169,8 +168,13 @@ st-mono| simpleterm monocolor, rs1=\Ec, rs2=\E[4l\E>\E[?1034l, sc=\E7, - sitm=\E[3m, + setab=\E[4%p1%dm, + setaf=\E[3%p1%dm, + setb=\E[4%?%p1%{1}%=%t4%e%p1%{3}%=%t6%e%p1%{4}%=%t1%e%p1%{6}%=%t3%e%p1%d%;m, + setf=\E[3%?%p1%{1}%=%t4%e%p1%{3}%=%t6%e%p1%{4}%=%t1%e%p1%{6}%=%t3%e%p1%d%;m, sgr0=\E[0m, + sgr=%?%p9%t\E(0%e\E(B%;\E[0%?%p6%t;1%;%?%p2%t;4%;%?%p1%p3%|%t;7%;%?%p4%t;5%;%?%p7%t;8%;m, + sitm=\E[3m, smacs=\E(0, smcup=\E[?1049h, smir=\E[4h, @@ -184,23 +188,12 @@ st-mono| simpleterm monocolor, # XTerm extensions rmxx=\E[29m, smxx=\E[9m, -# disabled rep for now: causes some issues with older ncurses versions. -# rep=%p1%c\E[%p2%{1}%-%db, # tmux extensions, see TERMINFO EXTENSIONS in tmux(1) Tc, Ms=\E]52;%p1%s;%p2%s\007, Se=\E[2 q, Ss=\E[%p1%d q, -st| simpleterm, - use=st-mono, - colors#8, - setab=\E[4%p1%dm, - setaf=\E[3%p1%dm, - setb=\E[4%?%p1%{1}%=%t4%e%p1%{3}%=%t6%e%p1%{4}%=%t1%e%p1%{6}%=%t3%e%p1%d%;m, - setf=\E[3%?%p1%{1}%=%t4%e%p1%{3}%=%t6%e%p1%{4}%=%t1%e%p1%{6}%=%t3%e%p1%d%;m, - sgr=%?%p9%t\E(0%e\E(B%;\E[0%?%p6%t;1%;%?%p2%t;4%;%?%p1%p3%|%t;7%;%?%p4%t;5%;%?%p7%t;8%;m, - st-256color| simpleterm with 256 colors, use=st, ccc, @@ -227,13 +220,3 @@ st-meta-256color| simpleterm with meta key and 256 colors, smm=\E[?1034h, rs2=\E[4l\E>\E[?1034h, is2=\E[4l\E>\E[?1034h, - -st-bs| simpleterm with backspace as backspace, - use=st, - kbs=\010, - kdch1=\177, - -st-bs-256color| simpleterm with backspace as backspace and 256colors, - use=st-256color, - kbs=\010, - kdch1=\177, @@ -30,7 +30,6 @@ void xdrawline(Line, int, int, int); void xfinishdraw(void); void xloadcols(void); int xsetcolorname(int, const char *); -void xseticontitle(char *); void xsettitle(char *); int xsetcursor(int); void xsetmode(int, unsigned int); @@ -38,3 +37,4 @@ void xsetpointermotion(int); void xsetsel(char *); int xstartdraw(void); void xximspot(int, int); +void xclearwin(void); @@ -16,7 +16,7 @@ #include <X11/XKBlib.h> #include <X11/Xresource.h> -char *argv0; +static char *argv0; #include "arg.h" #include "st.h" #include "win.h" @@ -31,11 +31,9 @@ typedef struct { } Shortcut; typedef struct { - uint mod; - uint button; - void (*func)(const Arg *); - const Arg arg; - uint release; + uint b; + uint mask; + char *s; } MouseShortcut; typedef struct { @@ -74,7 +72,6 @@ static void changealpha(const Arg *); static void zoom(const Arg *); static void zoomabs(const Arg *); static void zoomreset(const Arg *); -static void ttysend(const Arg *); /* config.h for applying patches and the configuration. */ #include "config.h" @@ -97,8 +94,10 @@ typedef XftGlyphFontSpec GlyphFontSpec; typedef struct { int tw, th; /* tty width and height */ int w, h; /* window width and height */ + int hborderpx, vborderpx; int ch; /* char height */ int cw; /* char width */ + int cyo; /* char y offset */ int mode; /* window state/mode flags */ int cursor; /* cursor style */ } TermWindow; @@ -109,13 +108,9 @@ typedef struct { Window win; Drawable buf; GlyphFontSpec *specbuf; /* font spec buffer used for rendering */ - Atom xembed, wmdeletewin, netwmname, netwmiconname, netwmpid; - struct { - XIM xim; - XIC xic; - XPoint spot; - XVaNestedList spotlist; - } ime; + Atom xembed, wmdeletewin, netwmname, netwmpid; + XIM xim; + XIC xic; Draw draw; Visual *vis; XSetWindowAttributes attrs; @@ -159,14 +154,13 @@ typedef struct { 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 xdrawglyphfontspecs(const XftGlyphFontSpec *, Glyph, int, int, int, int); static void xdrawglyph(Glyph, int, int); static void xclear(int, int, int, int); static int xgeommasktogravity(int); -static int ximopen(Display *); +static void ximopen(Display *); static void ximinstantiate(Display *, XPointer, XPointer); static void ximdestroy(XIM, XPointer, XPointer); -static int xicdestroy(XIC, XPointer, XPointer); static void xinit(int, int); static void cresize(int, int); static void xresize(int, int); @@ -190,8 +184,6 @@ static void kpress(XEvent *); static void cmessage(XEvent *); static void resize(XEvent *); static void focus(XEvent *); -static uint buttonmask(uint); -static int mouseaction(XEvent *, uint); static void brelease(XEvent *); static void bpress(XEvent *); static void bmotion(XEvent *); @@ -357,16 +349,10 @@ zoomreset(const Arg *arg) } } -void -ttysend(const Arg *arg) -{ - ttywrite(arg->s, strlen(arg->s), 1); -} - int evcol(XEvent *e) { - int x = e->xbutton.x - borderpx; + int x = e->xbutton.x - win.hborderpx; LIMIT(x, 0, win.tw - 1); return x / win.cw; } @@ -374,7 +360,7 @@ evcol(XEvent *e) int evrow(XEvent *e) { - int y = e->xbutton.y - borderpx; + int y = e->xbutton.y - win.vborderpx; LIMIT(y, 0, win.th - 1); return y / win.ch; } @@ -383,7 +369,7 @@ void mousesel(XEvent *e, int done) { int type, seltype = SEL_REGULAR; - uint state = e->xbutton.state & ~(Button1Mask | forcemousemod); + uint state = e->xbutton.state & ~(Button1Mask | forceselmod); for (type = 1; type < LEN(selmasks); ++type) { if (match(selmasks[type], state)) { @@ -459,51 +445,36 @@ mousereport(XEvent *e) ttywrite(buf, len, 0); } -uint -buttonmask(uint button) -{ - return button == Button1 ? Button1Mask - : button == Button2 ? Button2Mask - : button == Button3 ? Button3Mask - : button == Button4 ? Button4Mask - : button == Button5 ? Button5Mask - : 0; -} - -int -mouseaction(XEvent *e, uint release) -{ - MouseShortcut *ms; - - /* ignore Button<N>mask for Button<N> - it's set on release */ - uint state = e->xbutton.state & ~buttonmask(e->xbutton.button); - - for (ms = mshortcuts; ms < mshortcuts + LEN(mshortcuts); ms++) { - if (ms->release == release && - ms->button == e->xbutton.button && - (match(ms->mod, state) || /* exact or forced */ - match(ms->mod, state & ~forcemousemod))) { - ms->func(&(ms->arg)); - return 1; - } - } - - return 0; -} - void bpress(XEvent *e) { struct timespec now; + MouseShortcut *ms; + MouseKey *mk; int snap; - if (IS_SET(MODE_MOUSE) && !(e->xbutton.state & forcemousemod)) { + if (IS_SET(MODE_MOUSE) && !(e->xbutton.state & forceselmod)) { mousereport(e); return; } - if (mouseaction(e, 0)) - return; + if (tisaltscr()) { + for (ms = mshortcuts; ms < mshortcuts + LEN(mshortcuts); ms++) { + if (e->xbutton.button == ms->b + && match(ms->mask, e->xbutton.state)) { + ttywrite(ms->s, strlen(ms->s), 1); + return; + } + } + } + + for (mk = mkeys; mk < mkeys + LEN(mkeys); mk++) { + if (e->xbutton.button == mk->b + && match(mk->mask, e->xbutton.state)) { + mk->func(&mk->arg); + return; + } + } if (e->xbutton.button == Button1) { /* @@ -719,21 +690,21 @@ xsetsel(char *str) void brelease(XEvent *e) { - if (IS_SET(MODE_MOUSE) && !(e->xbutton.state & forcemousemod)) { + if (IS_SET(MODE_MOUSE) && !(e->xbutton.state & forceselmod)) { mousereport(e); return; } - if (mouseaction(e, 1)) - return; - if (e->xbutton.button == Button1) + 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 & forcemousemod)) { + if (IS_SET(MODE_MOUSE) && !(e->xbutton.state & forceselmod)) { mousereport(e); return; } @@ -756,6 +727,9 @@ cresize(int width, int height) col = MAX(1, col); row = MAX(1, row); + win.hborderpx = (win.w - col * win.cw) / 2; + win.vborderpx = (win.h - row * win.ch) / 2; + tresize(col, row); xresize(col, row); ttyresize(win.tw, win.th); @@ -834,6 +808,12 @@ xloadcols(void) if (opt_alpha) alpha = strtof(opt_alpha, NULL); dc.col[defaultbg].color.alpha = (unsigned short)(0xffff * alpha); + dc.col[defaultbg].color.red = + ((unsigned short)(dc.col[defaultbg].color.red * alpha)) & 0xff00; + dc.col[defaultbg].color.green = + ((unsigned short)(dc.col[defaultbg].color.green * alpha)) & 0xff00; + dc.col[defaultbg].color.blue = + ((unsigned short)(dc.col[defaultbg].color.blue * alpha)) & 0xff00; dc.col[defaultbg].pixel &= 0x00FFFFFF; dc.col[defaultbg].pixel |= (unsigned char)(0xff * alpha) << 24; loaded = 1; @@ -852,6 +832,8 @@ xsetcolorname(int x, const char *name) XftColorFree(xw.dpy, xw.vis, xw.cmap, &dc.col[x]); dc.col[x] = ncolor; + if (x == defaultbg) + dc.col[defaultbg].color.alpha = (unsigned short)(0xffff * alpha); return 0; } @@ -868,6 +850,13 @@ xclear(int x1, int y1, int x2, int y2) } void +xclearwin(void) +{ + xclear(0, 0, win.w, win.h); +} + + +void xhints(void) { XClassHint class = {opt_name ? opt_name : "st", @@ -880,8 +869,8 @@ xhints(void) 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->height_inc = 1; + sizeh->width_inc = 1; sizeh->base_height = 2 * borderpx; sizeh->base_width = 2 * borderpx; sizeh->min_height = win.ch + 2 * borderpx; @@ -1042,6 +1031,7 @@ xloadfonts(char *fontstr, double fontsize) /* Setting character width and height. */ win.cw = ceilf(dc.font.width * cwscale); win.ch = ceilf(dc.font.height * chscale); + win.cyo = ceilf(dc.font.height * (chscale - 1) / 2); FcPatternDel(pattern, FC_SLANT); FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ITALIC); @@ -1181,58 +1171,41 @@ xunloadfonts(void) xunloadfont(&dc.ibfont); } -int +void ximopen(Display *dpy) { - XIMCallback imdestroy = { .client_data = NULL, .callback = ximdestroy }; - XICCallback icdestroy = { .client_data = NULL, .callback = xicdestroy }; - - xw.ime.xim = XOpenIM(xw.dpy, NULL, NULL, NULL); - if (xw.ime.xim == NULL) - return 0; - - if (XSetIMValues(xw.ime.xim, XNDestroyCallback, &imdestroy, NULL)) - fprintf(stderr, "XSetIMValues: " - "Could not set XNDestroyCallback.\n"); + XIMCallback destroy = { .client_data = NULL, .callback = ximdestroy }; - xw.ime.spotlist = XVaCreateNestedList(0, XNSpotLocation, &xw.ime.spot, - NULL); - - if (xw.ime.xic == NULL) { - xw.ime.xic = XCreateIC(xw.ime.xim, XNInputStyle, - XIMPreeditNothing | XIMStatusNothing, - XNClientWindow, xw.win, - XNDestroyCallback, &icdestroy, - NULL); + if ((xw.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 (xw.ime.xic == NULL) - fprintf(stderr, "XCreateIC: Could not create input context.\n"); - - return 1; + 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) { - if (ximopen(dpy)) - XUnregisterIMInstantiateCallback(xw.dpy, NULL, NULL, NULL, - ximinstantiate, NULL); + ximopen(dpy); + XUnregisterIMInstantiateCallback(xw.dpy, NULL, NULL, NULL, + ximinstantiate, NULL); } void ximdestroy(XIM xim, XPointer client, XPointer call) { - xw.ime.xim = NULL; + xw.xim = NULL; XRegisterIMInstantiateCallback(xw.dpy, NULL, NULL, NULL, - ximinstantiate, NULL); - XFree(xw.ime.spotlist); -} - -int -xicdestroy(XIC xim, XPointer client, XPointer call) -{ - xw.ime.xic = NULL; - return 1; + ximinstantiate, NULL); } void @@ -1274,8 +1247,8 @@ xinit(int cols, int rows) xloadcols(); /* adjust fixed window geometry */ - win.w = 2 * borderpx + cols * win.cw; - win.h = 2 * borderpx + rows * win.ch; + win.w = 2 * win.hborderpx + cols * win.cw; + win.h = 2 * win.vborderpx + rows * win.ch; if (xw.gm & XNegative) xw.l += DisplayWidth(xw.dpy, xw.scr) - win.w - 2; if (xw.gm & YNegative) @@ -1309,10 +1282,7 @@ xinit(int cols, int rows) xw.draw = XftDrawCreate(xw.dpy, xw.buf, xw.vis, xw.cmap); /* input methods */ - if (!ximopen(xw.dpy)) { - XRegisterIMInstantiateCallback(xw.dpy, NULL, NULL, NULL, - ximinstantiate, NULL); - } + ximopen(xw.dpy); /* white cursor, black outline */ cursor = XCreateFontCursor(xw.dpy, mouseshape); @@ -1335,7 +1305,6 @@ xinit(int cols, int rows) xw.xembed = XInternAtom(xw.dpy, "_XEMBED", False); xw.wmdeletewin = XInternAtom(xw.dpy, "WM_DELETE_WINDOW", False); xw.netwmname = XInternAtom(xw.dpy, "_NET_WM_NAME", False); - xw.netwmiconname = XInternAtom(xw.dpy, "_NET_WM_ICON_NAME", False); XSetWMProtocols(xw.dpy, xw.win, &xw.wmdeletewin, 1); xw.netwmpid = XInternAtom(xw.dpy, "_NET_WM_PID", False); @@ -1344,8 +1313,8 @@ xinit(int cols, int rows) win.mode = MODE_NUMLOCK; resettitle(); - xhints(); XMapWindow(xw.dpy, xw.win); + xhints(); XSync(xw.dpy, False); clock_gettime(CLOCK_MONOTONIC, &xsel.tclick1); @@ -1362,7 +1331,7 @@ xinit(int cols, int rows) 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; + float winx = win.hborderpx + x * win.cw, winy = win.vborderpx + y * win.ch, xp, yp; ushort mode, prevmode = USHRT_MAX; Font *font = &dc.font; int frcflags = FRC_NORMAL; @@ -1375,7 +1344,7 @@ xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x FcCharSet *fccharset; int i, f, numspecs = 0; - for (i = 0, xp = winx, yp = winy + font->ascent; i < len; ++i) { + for (i = 0, xp = winx, yp = winy + font->ascent + win.cyo; i < len; ++i) { /* Fetch rune and mode for current glyph. */ rune = glyphs[i].u; mode = glyphs[i].mode; @@ -1400,7 +1369,7 @@ xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x font = &dc.bfont; frcflags = FRC_BOLD; } - yp = winy + font->ascent; + yp = winy + font->ascent + win.cyo; } if (mode & ATTR_BOXDRAW) { @@ -1500,14 +1469,13 @@ xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x } void -xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, int y) +xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, int y, int dmode) { int charlen = len * ((base.mode & ATTR_WIDE) ? 2 : 1); - int winx = borderpx + x * win.cw, winy = borderpx + y * win.ch, + int winx = win.hborderpx + x * win.cw, winy = win.vborderpx + 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) { @@ -1540,10 +1508,6 @@ xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, i 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]; @@ -1591,51 +1555,45 @@ xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, i 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); - - if (base.mode & ATTR_BOXDRAW) { - drawboxes(winx, winy, width / len, win.ch, fg, bg, specs, len); - } else { - /* Render the glyphs. */ - XftDrawGlyphFontSpec(xw.draw, fg, specs, len); - } + if (dmode & DRAW_BG) { + /* Intelligent cleaning up of the borders. */ + if (x == 0) { + xclear(0, (y == 0)? 0 : winy, win.vborderpx, + winy + win.ch + + ((winy + win.ch >= win.vborderpx + win.th)? win.h : 0)); + } + if (winx + width >= win.hborderpx + win.tw) { + xclear(winx + width, (y == 0)? 0 : winy, win.w, + ((winy + win.ch >= win.vborderpx + win.th)? win.h : (winy + win.ch))); + } + if (y == 0) + xclear(winx, 0, winx + width, win.hborderpx); + if (winy + win.ch >= win.vborderpx + win.th) + xclear(winx, winy + win.ch, winx + width, win.h); - /* Render underline and strikethrough. */ - if (base.mode & ATTR_UNDERLINE) { - XftDrawRect(xw.draw, fg, winx, winy + dc.font.ascent + 1, - width, 1); + /* Fill the background */ + XftDrawRect(xw.draw, bg, winx, winy, width, win.ch); } - if (base.mode & ATTR_STRUCK) { - XftDrawRect(xw.draw, fg, winx, winy + 2 * dc.font.ascent / 3, - width, 1); - } + if (dmode & DRAW_FG) { + if (base.mode & ATTR_BOXDRAW) { + drawboxes(winx, winy, width / len, win.ch, fg, bg, specs, len); + } else { + /* Render the glyphs. */ + XftDrawGlyphFontSpec(xw.draw, fg, specs, len); + } + + /* Render underline and strikethrough. */ + if (base.mode & ATTR_UNDERLINE) { + XftDrawRect(xw.draw, fg, winx, winy + win.cyo + dc.font.ascent + 1, + width, 1); + } - /* Reset clip to none. */ - XftDrawSetClip(xw.draw, 0); + if (base.mode & ATTR_STRUCK) { + XftDrawRect(xw.draw, fg, winx, winy + win.cyo + 2 * dc.font.ascent / 3, + width, 1); + } + } } void @@ -1645,7 +1603,7 @@ xdrawglyph(Glyph g, int x, int y) XftGlyphFontSpec spec; numspecs = xmakeglyphfontspecs(&spec, &g, 1, x, y); - xdrawglyphfontspecs(&spec, g, numspecs, x, y); + xdrawglyphfontspecs(&spec, g, numspecs, x, y, DRAW_BG | DRAW_FG); } void @@ -1693,9 +1651,8 @@ xdrawcursor(int cx, int cy, Glyph g, int ox, int oy, Glyph og, Line line, int le /* draw the new one */ if (IS_SET(MODE_FOCUSED)) { switch (win.cursor) { - case 7: /* st extension */ - g.u = 0x2603; /* snowman (U+2603) */ - /* FALLTHROUGH */ + case 7: /* st extension: snowman (U+2603) */ + g.u = 0x2603; case 0: /* Blinking Block */ case 1: /* Blinking Block (Default) */ case 2: /* Steady Block */ @@ -1704,35 +1661,35 @@ xdrawcursor(int cx, int cy, Glyph g, int ox, int oy, Glyph og, Line line, int le case 3: /* Blinking Underline */ case 4: /* Steady Underline */ XftDrawRect(xw.draw, &drawcol, - borderpx + cx * win.cw, - borderpx + (cy + 1) * win.ch - \ + win.hborderpx + cx * win.cw, + win.vborderpx + (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, + win.hborderpx + cx * win.cw, + win.vborderpx + cy * win.ch, cursorthickness, win.ch); break; } } else { XftDrawRect(xw.draw, &drawcol, - borderpx + cx * win.cw, - borderpx + cy * win.ch, + win.hborderpx + cx * win.cw, + win.vborderpx + cy * win.ch, win.cw - 1, 1); XftDrawRect(xw.draw, &drawcol, - borderpx + cx * win.cw, - borderpx + cy * win.ch, + win.hborderpx + cx * win.cw, + win.vborderpx + cy * win.ch, 1, win.ch - 1); XftDrawRect(xw.draw, &drawcol, - borderpx + (cx + 1) * win.cw - 1, - borderpx + cy * win.ch, + win.hborderpx + (cx + 1) * win.cw - 1, + win.vborderpx + cy * win.ch, 1, win.ch - 1); XftDrawRect(xw.draw, &drawcol, - borderpx + cx * win.cw, - borderpx + (cy + 1) * win.ch - 1, + win.hborderpx + cx * win.cw, + win.vborderpx + (cy + 1) * win.ch - 1, win.cw, 1); } } @@ -1747,19 +1704,6 @@ xsetenv(void) } void -xseticontitle(char *p) -{ - XTextProperty prop; - DEFAULT(p, opt_title); - - Xutf8TextListToTextProperty(xw.dpy, &p, 1, XUTF8StringStyle, - &prop); - XSetWMIconName(xw.dpy, xw.win, &prop); - XSetTextProperty(xw.dpy, xw.win, &prop, xw.netwmiconname); - XFree(prop.value); -} - -void xsettitle(char *p) { XTextProperty prop; @@ -1781,32 +1725,39 @@ xstartdraw(void) void xdrawline(Line line, int x1, int y1, int x2) { - int i, x, ox, numspecs; + int i, x, ox, numspecs, numspecs_cached; 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; + XftGlyphFontSpec *specs; + + numspecs_cached = xmakeglyphfontspecs(xw.specbuf, &line[x1], x2 - x1, x1, y1); + + /* Draw line in 2 passes: background and foreground. This way wide glyphs + won't get truncated (#223) */ + for (int dmode = DRAW_BG; dmode <= DRAW_FG; dmode <<= 1) { + specs = xw.specbuf; + numspecs = numspecs_cached; + 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, dmode); + specs += i; + numspecs -= i; + i = 0; + } + if (i == 0) { + ox = x; + base = new; + } + i++; } - i++; + if (i > 0) + xdrawglyphfontspecs(specs, base, i, ox, y1, dmode); } - if (i > 0) - xdrawglyphfontspecs(specs, base, i, ox, y1); } void @@ -1822,13 +1773,11 @@ xfinishdraw(void) void xximspot(int x, int y) { - if (xw.ime.xic == NULL) - return; + XPoint spot = { borderpx + x * win.cw, borderpx + (y + 1) * win.ch }; + XVaNestedList attr = XVaCreateNestedList(0, XNSpotLocation, &spot, NULL); - xw.ime.spot.x = borderpx + x * win.cw; - xw.ime.spot.y = borderpx + (y + 1) * win.ch; - - XSetICValues(xw.ime.xic, XNPreeditAttributes, xw.ime.spotlist, NULL); + XSetICValues(xw.xic, XNPreeditAttributes, attr, NULL); + XFree(attr); } void @@ -1870,7 +1819,8 @@ xsetmode(int set, unsigned int flags) int xsetcursor(int cursor) { - if (!BETWEEN(cursor, 0, 7)) /* 7: st extension */ + DEFAULT(cursor, 1); + if (!BETWEEN(cursor, 0, 6)) return 1; win.cursor = cursor; return 0; @@ -1904,15 +1854,13 @@ focus(XEvent *ev) return; if (ev->type == FocusIn) { - if (xw.ime.xic) - XSetICFocus(xw.ime.xic); + XSetICFocus(xw.xic); win.mode |= MODE_FOCUSED; xseturgency(0); if (IS_SET(MODE_FOCUS)) ttywrite("\033[I", 3, 0); } else { - if (xw.ime.xic) - XUnsetICFocus(xw.ime.xic); + XUnsetICFocus(xw.xic); win.mode &= ~MODE_FOCUSED; if (IS_SET(MODE_FOCUS)) ttywrite("\033[O", 3, 0); @@ -1967,7 +1915,7 @@ kpress(XEvent *ev) { XKeyEvent *e = &ev->xkey; KeySym ksym; - char buf[64], *customkey; + char buf[32], *customkey; int len; Rune c; Status status; @@ -1976,10 +1924,7 @@ kpress(XEvent *ev) if (IS_SET(MODE_KBDLOCK)) return; - if (xw.ime.xic) - len = XmbLookupString(xw.ime.xic, e, buf, sizeof buf, &ksym, &status); - else - len = XLookupString(e, buf, sizeof buf, &ksym, NULL); + 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)) { @@ -2107,7 +2052,7 @@ run(void) * triggers drawing, we first wait a bit to ensure we got * everything, and if nothing new arrives - we draw. * We start with trying to wait minlatency ms. If more content - * arrives sooner, we retry with shorter and shorter periods, + * arrives sooner, we retry with shorter and shorter preiods, * and eventually draw even without idle after maxlatency ms. * Typically this results in low latency while interacting, * maximum latency intervals during `cat huge.txt`, and perfect @@ -2215,7 +2160,7 @@ main(int argc, char *argv[]) { xw.l = xw.t = 0; xw.isfixed = False; - xsetcursor(cursorshape); + win.cursor = cursorshape; ARGBEGIN { case 'a': |
