mirror of
https://github.com/StepanovPlaton/st.git
synced 2026-04-03 12:20:43 +04:00
New build
This commit is contained in:
253
FAQ
Normal file
253
FAQ
Normal file
@@ -0,0 +1,253 @@
|
||||
## Why does st not handle utmp entries?
|
||||
|
||||
Use the excellent tool of [utmp](https://git.suckless.org/utmp/) for this task.
|
||||
|
||||
|
||||
## Some _random program_ complains that st is unknown/not recognised/unsupported/whatever!
|
||||
|
||||
It means that st doesn’t have any terminfo entry on your system. Chances are
|
||||
you did not `make install`. If you just want to test it without installing it,
|
||||
you can manually run `tic -sx st.info`.
|
||||
|
||||
|
||||
## Nothing works, and nothing is said about an unknown terminal!
|
||||
|
||||
* Some programs just assume they’re running in xterm i.e. they don’t rely on
|
||||
terminfo. What you see is the current state of the “xterm compliance”.
|
||||
* Some programs don’t complain about the lacking st description and default to
|
||||
another terminal. In that case see the question about terminfo.
|
||||
|
||||
|
||||
## How do I scroll back up?
|
||||
|
||||
* Using a terminal multiplexer.
|
||||
* `st -e tmux` using C-b [
|
||||
* `st -e screen` using C-a ESC
|
||||
* Using the excellent tool of [scroll](https://git.suckless.org/scroll/).
|
||||
* Using the scrollback [patch](https://st.suckless.org/patches/scrollback/).
|
||||
|
||||
|
||||
## I would like to have utmp and/or scroll functionality by default
|
||||
|
||||
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?
|
||||
|
||||
Taken from the terminfo manpage:
|
||||
|
||||
If the terminal has a keypad that transmits codes when the keys
|
||||
are pressed, this information can be given. Note that it is not
|
||||
possible to handle terminals where the keypad only works in
|
||||
local (this applies, for example, to the unshifted HP 2621 keys).
|
||||
If the keypad can be set to transmit or not transmit, give these
|
||||
codes as smkx and rmkx. Otherwise the keypad is assumed to
|
||||
always transmit.
|
||||
|
||||
In the st case smkx=E[?1hE= and rmkx=E[?1lE>, so it is mandatory that
|
||||
applications which want to test against keypad keys send these
|
||||
sequences.
|
||||
|
||||
But buggy applications (like bash and irssi, for example) don't do this. A fast
|
||||
solution for them is to use the following command:
|
||||
|
||||
$ printf '\033[?1h\033=' >/dev/tty
|
||||
|
||||
or
|
||||
$ tput smkx
|
||||
|
||||
In the case of bash, readline is used. Readline has a different note in its
|
||||
manpage about this issue:
|
||||
|
||||
enable-keypad (Off)
|
||||
When set to On, readline will try to enable the
|
||||
application keypad when it is called. Some systems
|
||||
need this to enable arrow keys.
|
||||
|
||||
Adding this option to your .inputrc will fix the keypad problem for all
|
||||
applications using readline.
|
||||
|
||||
If you are using zsh, then read the zsh FAQ
|
||||
<http://zsh.sourceforge.net/FAQ/zshfaq03.html#l25>:
|
||||
|
||||
It should be noted that the O / [ confusion can occur with other keys
|
||||
such as Home and End. Some systems let you query the key sequences
|
||||
sent by these keys from the system's terminal database, terminfo.
|
||||
Unfortunately, the key sequences given there typically apply to the
|
||||
mode that is not the one zsh uses by default (it's the "application"
|
||||
mode rather than the "raw" mode). Explaining the use of terminfo is
|
||||
outside of the scope of this FAQ, but if you wish to use the key
|
||||
sequences given there you can tell the line editor to turn on
|
||||
"application" mode when it starts and turn it off when it stops:
|
||||
|
||||
function zle-line-init () { echoti smkx }
|
||||
function zle-line-finish () { echoti rmkx }
|
||||
zle -N zle-line-init
|
||||
zle -N zle-line-finish
|
||||
|
||||
Putting these lines into your .zshrc will fix the problems.
|
||||
|
||||
|
||||
## How can I use meta in 8bit mode?
|
||||
|
||||
St supports meta in 8bit mode, but the default terminfo entry doesn't
|
||||
use this capability. If you want it, you have to use the 'st-meta' value
|
||||
in TERM.
|
||||
|
||||
|
||||
## I cannot compile st in OpenBSD
|
||||
|
||||
OpenBSD lacks librt, despite it being mandatory in POSIX
|
||||
<http://pubs.opengroup.org/onlinepubs/9699919799/utilities/c99.html#tag_20_11_13>.
|
||||
If you want to compile st for OpenBSD you have to remove -lrt from config.mk, and
|
||||
st will compile without any loss of functionality, because all the functions are
|
||||
included in libc on this platform.
|
||||
|
||||
|
||||
## The Backspace Case
|
||||
|
||||
St is emulating the Linux way of handling backspace being delete and delete being
|
||||
backspace.
|
||||
|
||||
This is an issue that was discussed in suckless mailing list
|
||||
<https://lists.suckless.org/dev/1404/20697.html>. Here is why some old grumpy
|
||||
terminal users wants its backspace to be how he feels it:
|
||||
|
||||
Well, I am going to comment why I want to change the behaviour
|
||||
of this key. When ASCII was defined in 1968, communication
|
||||
with computers was done using punched cards, or hardcopy
|
||||
terminals (basically a typewriter machine connected with the
|
||||
computer using a serial port). ASCII defines DELETE as 7F,
|
||||
because, in punched-card terms, it means all the holes of the
|
||||
card punched; it is thus a kind of 'physical delete'. In the
|
||||
same way, the BACKSPACE key was a non-destructive backspace,
|
||||
as on a typewriter. So, if you wanted to delete a character,
|
||||
you had to BACKSPACE and then DELETE. Another use of BACKSPACE
|
||||
was to type accented characters, for example 'a BACKSPACE `'.
|
||||
The VT100 had no BACKSPACE key; it was generated using the
|
||||
CONTROL key as another control character (CONTROL key sets to
|
||||
0 b7 b6 b5, so it converts H (code 0x48) into BACKSPACE (code
|
||||
0x08)), but it had a DELETE key in a similar position where
|
||||
the BACKSPACE key is located today on common PC keyboards.
|
||||
All the terminal emulators emulated the difference between
|
||||
these keys correctly: the backspace key generated a BACKSPACE
|
||||
(^H) and delete key generated a DELETE (^?).
|
||||
|
||||
But a problem arose when Linus Torvalds wrote Linux. Unlike
|
||||
earlier terminals, the Linux virtual terminal (the terminal
|
||||
emulator integrated in the kernel) returned a DELETE when
|
||||
backspace was pressed, due to the VT100 having a DELETE key in
|
||||
the same position. This created a lot of problems (see [1]
|
||||
and [2]). Since Linux has become the king, a lot of terminal
|
||||
emulators today generate a DELETE when the backspace key is
|
||||
pressed in order to avoid problems with Linux. The result is
|
||||
that the only way of generating a BACKSPACE on these systems
|
||||
is by using CONTROL + H. (I also think that emacs had an
|
||||
important point here because the CONTROL + H prefix is used
|
||||
in emacs in some commands (help commands).)
|
||||
|
||||
From point of view of the kernel, you can change the key
|
||||
for deleting a previous character with stty erase. When you
|
||||
connect a real terminal into a machine you describe the type
|
||||
of terminal, so getty configures the correct value of stty
|
||||
erase for this terminal. In the case of terminal emulators,
|
||||
however, you don't have any getty that can set the correct
|
||||
value of stty erase, so you always get the default value.
|
||||
For this reason, it is necessary to add 'stty erase ^H' to your
|
||||
profile if you have changed the value of the backspace key.
|
||||
Of course, another solution is for st itself to modify the
|
||||
value of stty erase. I usually have the inverse problem:
|
||||
when I connect to non-Unix machines, I have to press CONTROL +
|
||||
h to get a BACKSPACE. The inverse problem occurs when a user
|
||||
connects to my Unix machines from a different system with a
|
||||
correct backspace key.
|
||||
|
||||
[1] http://www.ibb.net/~anne/keyboard.html
|
||||
[2] http://www.tldp.org/HOWTO/Keyboard-and-Console-HOWTO-5.html
|
||||
|
||||
|
||||
## But I really want the old grumpy behaviour of my terminal
|
||||
|
||||
Apply [1].
|
||||
|
||||
[1] https://st.suckless.org/patches/delkey
|
||||
|
||||
|
||||
## Why do images not work in st using the w3m image hack?
|
||||
|
||||
w3mimg uses a hack that draws an image on top of the terminal emulator Drawable
|
||||
window. The hack relies on the terminal to use a single buffer to draw its
|
||||
contents directly.
|
||||
|
||||
st uses double-buffered drawing so the image is quickly replaced and may show a
|
||||
short flicker effect.
|
||||
|
||||
Below is a patch example to change st double-buffering to a single Drawable
|
||||
buffer.
|
||||
|
||||
diff --git a/x.c b/x.c
|
||||
--- a/x.c
|
||||
+++ b/x.c
|
||||
@@ -732,10 +732,6 @@ xresize(int col, int row)
|
||||
win.tw = col * win.cw;
|
||||
win.th = row * win.ch;
|
||||
|
||||
- XFreePixmap(xw.dpy, xw.buf);
|
||||
- xw.buf = XCreatePixmap(xw.dpy, xw.win, win.w, win.h,
|
||||
- DefaultDepth(xw.dpy, xw.scr));
|
||||
- XftDrawChange(xw.draw, xw.buf);
|
||||
xclear(0, 0, win.w, win.h);
|
||||
|
||||
/* resize to new width */
|
||||
@@ -1148,8 +1144,7 @@ xinit(int cols, int rows)
|
||||
gcvalues.graphics_exposures = False;
|
||||
dc.gc = XCreateGC(xw.dpy, parent, GCGraphicsExposures,
|
||||
&gcvalues);
|
||||
- xw.buf = XCreatePixmap(xw.dpy, xw.win, win.w, win.h,
|
||||
- DefaultDepth(xw.dpy, xw.scr));
|
||||
+ xw.buf = xw.win;
|
||||
XSetForeground(xw.dpy, dc.gc, dc.col[defaultbg].pixel);
|
||||
XFillRectangle(xw.dpy, xw.buf, dc.gc, 0, 0, win.w, win.h);
|
||||
|
||||
@@ -1632,8 +1627,6 @@ xdrawline(Line line, int x1, int y1, int x2)
|
||||
void
|
||||
xfinishdraw(void)
|
||||
{
|
||||
- XCopyArea(xw.dpy, xw.buf, xw.win, dc.gc, 0, 0, win.w,
|
||||
- win.h, 0, 0);
|
||||
XSetForeground(xw.dpy, dc.gc,
|
||||
dc.col[IS_SET(MODE_REVERSE)?
|
||||
defaultfg : defaultbg].pixel);
|
||||
|
||||
|
||||
## BadLength X error in Xft when trying to render emoji
|
||||
|
||||
Xft makes st crash when rendering color emojis with the following error:
|
||||
|
||||
"X Error of failed request: BadLength (poly request too large or internal Xlib length error)"
|
||||
Major opcode of failed request: 139 (RENDER)
|
||||
Minor opcode of failed request: 20 (RenderAddGlyphs)
|
||||
Serial number of failed request: 1595
|
||||
Current serial number in output stream: 1818"
|
||||
|
||||
This is a known bug in Xft (not st) which happens on some platforms and
|
||||
combination of particular fonts and fontconfig settings.
|
||||
|
||||
See also:
|
||||
https://gitlab.freedesktop.org/xorg/lib/libxft/issues/6
|
||||
https://bugs.freedesktop.org/show_bug.cgi?id=107534
|
||||
https://bugzilla.redhat.com/show_bug.cgi?id=1498269
|
||||
|
||||
The solution is to remove color emoji fonts or disable this in the fontconfig
|
||||
XML configuration. As an ugly workaround (which may work only on newer
|
||||
fontconfig versions (FC_COLOR)), the following code can be used to mask color
|
||||
fonts:
|
||||
|
||||
FcPatternAddBool(fcpattern, FC_COLOR, FcFalse);
|
||||
|
||||
Please don't bother reporting this bug to st, but notify the upstream Xft
|
||||
developers about fixing this bug.
|
||||
|
||||
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
|
||||
17
LEGACY
Normal file
17
LEGACY
Normal file
@@ -0,0 +1,17 @@
|
||||
A STATEMENT ON LEGACY SUPPORT
|
||||
|
||||
In the terminal world there is much cruft that comes from old and unsup‐
|
||||
ported terminals that inherit incompatible modes and escape sequences
|
||||
which noone is able to know, except when he/she comes from that time and
|
||||
developed a graphical vt100 emulator at that time.
|
||||
|
||||
One goal of st is to only support what is really needed. When you en‐
|
||||
counter a sequence which you really need, implement it. But while you
|
||||
are at it, do not add the other cruft you might encounter while sneek‐
|
||||
ing at other terminal emulators. History has bloated them and there is
|
||||
no real evidence that most of the sequences are used today.
|
||||
|
||||
|
||||
Christoph Lohmann <20h@r-36.net>
|
||||
2012-09-13T07:00:36.081271045+02:00
|
||||
|
||||
10
Makefile
10
Makefile
@@ -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
|
||||
|
||||
34
README
Normal file
34
README
Normal file
@@ -0,0 +1,34 @@
|
||||
st - simple terminal
|
||||
--------------------
|
||||
st is a simple terminal emulator for X which sucks less.
|
||||
|
||||
|
||||
Requirements
|
||||
------------
|
||||
In order to build st you need the Xlib header files.
|
||||
|
||||
|
||||
Installation
|
||||
------------
|
||||
Edit config.mk to match your local setup (st is installed into
|
||||
the /usr/local namespace by default).
|
||||
|
||||
Afterwards enter the following command to build and install st (if
|
||||
necessary as root):
|
||||
|
||||
make clean install
|
||||
|
||||
|
||||
Running st
|
||||
----------
|
||||
If you did not install st with make clean install, you must compile
|
||||
the st terminfo entry with the following command:
|
||||
|
||||
tic -sx st.info
|
||||
|
||||
See the man page for additional details.
|
||||
|
||||
Credits
|
||||
-------
|
||||
Based on Aurélien APTEL <aurelien dot aptel at gmail dot com> bt source code.
|
||||
|
||||
28
TODO
Normal file
28
TODO
Normal file
@@ -0,0 +1,28 @@
|
||||
vt emulation
|
||||
------------
|
||||
|
||||
* double-height support
|
||||
|
||||
code & interface
|
||||
----------------
|
||||
|
||||
* add a simple way to do multiplexing
|
||||
|
||||
drawing
|
||||
-------
|
||||
* add diacritics support to xdraws()
|
||||
* switch to a suckless font drawing library
|
||||
* make the font cache simpler
|
||||
* add better support for brightening of the upper colors
|
||||
|
||||
bugs
|
||||
----
|
||||
|
||||
* fix shift up/down (shift selection in emacs)
|
||||
* remove DEC test sequence when appropriate
|
||||
|
||||
misc
|
||||
----
|
||||
|
||||
$ grep -nE 'XXX|TODO' st.c
|
||||
|
||||
94
config.def.h
94
config.def.h
@@ -5,7 +5,7 @@
|
||||
*
|
||||
* font: see http://freedesktop.org/software/fontconfig/fontconfig-user.html
|
||||
*/
|
||||
static char *font = "Liberation Mono:pixelsize=12:antialias=true:autohint=true";
|
||||
static char *font = "CodeNewRoman Nerd Font Mono:pixelsize=12:antialias=true:autohint=true";
|
||||
static int borderpx = 2;
|
||||
|
||||
/*
|
||||
@@ -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;
|
||||
|
||||
/*
|
||||
@@ -96,28 +96,26 @@ unsigned int tabspaces = 8;
|
||||
/* Terminal colors (16 first used in escape sequence) */
|
||||
static const char *colorname[] = {
|
||||
/* 8 normal colors */
|
||||
[0] = "#000000", /* black */
|
||||
[1] = "#ff5555", /* red */
|
||||
[2] = "#50fa7b", /* green */
|
||||
[3] = "#f1fa8c", /* yellow */
|
||||
[4] = "#bd93f9", /* blue */
|
||||
[5] = "#ff79c6", /* magenta */
|
||||
[6] = "#8be9fd", /* cyan */
|
||||
[7] = "#bbbbbb", /* white */
|
||||
"black",
|
||||
"red3",
|
||||
"green3",
|
||||
"yellow3",
|
||||
"blue2",
|
||||
"magenta3",
|
||||
"cyan3",
|
||||
"gray90",
|
||||
|
||||
/* 8 bright colors */
|
||||
[8] = "#44475a", /* black */
|
||||
[9] = "#ff5555", /* red */
|
||||
[10] = "#50fa7b", /* green */
|
||||
[11] = "#f1fa8c", /* yellow */
|
||||
[12] = "#bd93f9", /* blue */
|
||||
[13] = "#ff79c6", /* magenta */
|
||||
[14] = "#8be9fd", /* cyan */
|
||||
[15] = "#ffffff", /* white */
|
||||
"gray50",
|
||||
"red",
|
||||
"green",
|
||||
"yellow",
|
||||
"#5c5cff",
|
||||
"magenta",
|
||||
"cyan",
|
||||
"white",
|
||||
|
||||
/* special colors */
|
||||
[256] = "#282a36", /* background */
|
||||
[257] = "#f8f8f2", /* foreground */
|
||||
[255] = 0,
|
||||
|
||||
/* more colors can be added after 255 to use with DefaultXX */
|
||||
"#cccccc",
|
||||
@@ -129,21 +127,13 @@ static const char *colorname[] = {
|
||||
|
||||
/*
|
||||
* Default colors (colorname index)
|
||||
* foreground, background, cursor
|
||||
* foreground, background, cursor, reverse cursor
|
||||
*/
|
||||
unsigned int defaultfg = 257;
|
||||
unsigned int defaultbg = 256;
|
||||
unsigned int defaultcs = 257;
|
||||
unsigned int defaultfg = 258;
|
||||
unsigned int defaultbg = 259;
|
||||
unsigned int defaultcs = 256;
|
||||
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.
|
||||
*/
|
||||
unsigned int defaultitalic = 7;
|
||||
unsigned int defaultunderline = 7;
|
||||
|
||||
/*
|
||||
* Default shape of cursor
|
||||
* 2: Block ("█")
|
||||
@@ -180,6 +170,42 @@ static unsigned int defaultattr = 11;
|
||||
*/
|
||||
static uint forcemousemod = ShiftMask;
|
||||
|
||||
/*
|
||||
* Xresources preferences to load at startup
|
||||
*/
|
||||
ResourcePref resources[] = {
|
||||
{ "font", STRING, &font },
|
||||
{ "color0", STRING, &colorname[0] },
|
||||
{ "color1", STRING, &colorname[1] },
|
||||
{ "color2", STRING, &colorname[2] },
|
||||
{ "color3", STRING, &colorname[3] },
|
||||
{ "color4", STRING, &colorname[4] },
|
||||
{ "color5", STRING, &colorname[5] },
|
||||
{ "color6", STRING, &colorname[6] },
|
||||
{ "color7", STRING, &colorname[7] },
|
||||
{ "color8", STRING, &colorname[8] },
|
||||
{ "color9", STRING, &colorname[9] },
|
||||
{ "color10", STRING, &colorname[10] },
|
||||
{ "color11", STRING, &colorname[11] },
|
||||
{ "color12", STRING, &colorname[12] },
|
||||
{ "color13", STRING, &colorname[13] },
|
||||
{ "color14", STRING, &colorname[14] },
|
||||
{ "color15", STRING, &colorname[15] },
|
||||
{ "background", STRING, &colorname[259] },
|
||||
{ "foreground", STRING, &colorname[258] },
|
||||
{ "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 },
|
||||
{ "borderpx", INTEGER, &borderpx },
|
||||
{ "cwscale", FLOAT, &cwscale },
|
||||
{ "chscale", FLOAT, &chscale },
|
||||
};
|
||||
|
||||
/*
|
||||
* Internal mouse shortcuts.
|
||||
* Beware that overloading Button1 will disable the selection.
|
||||
@@ -211,6 +237,8 @@ static Shortcut shortcuts[] = {
|
||||
{ TERMMOD, XK_Y, selpaste, {.i = 0} },
|
||||
{ ShiftMask, XK_Insert, selpaste, {.i = 0} },
|
||||
{ TERMMOD, XK_Num_Lock, numlock, {.i = 0} },
|
||||
{ ShiftMask, XK_Page_Up, kscrollup, {.f = -0.1} },
|
||||
{ ShiftMask, XK_Page_Down, kscrolldown, {.f = -0.1} },
|
||||
};
|
||||
|
||||
/*
|
||||
|
||||
100
config.h
100
config.h
@@ -5,7 +5,7 @@
|
||||
*
|
||||
* font: see http://freedesktop.org/software/fontconfig/fontconfig-user.html
|
||||
*/
|
||||
static char *font = "CodeNewRoman Nerd Font Mono:pixelsize=18:antialias=true:autohint=true";
|
||||
static char *font = "CodeNewRoman Nerd Font Mono:pixelsize=12:antialias=true:autohint=true";
|
||||
static int borderpx = 2;
|
||||
|
||||
/*
|
||||
@@ -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;
|
||||
|
||||
/*
|
||||
@@ -96,28 +96,26 @@ unsigned int tabspaces = 8;
|
||||
/* Terminal colors (16 first used in escape sequence) */
|
||||
static const char *colorname[] = {
|
||||
/* 8 normal colors */
|
||||
[0] = "#000000", /* black */
|
||||
[1] = "#cf6a4c", /* red */
|
||||
[2] = "#99ad6a", /* green */
|
||||
[3] = "#d8ad4c", /* yellow */
|
||||
[4] = "#597bc5", /* blue */
|
||||
[5] = "#a037b0", /* magenta */
|
||||
[6] = "#71b9f8", /* cyan */
|
||||
[7] = "#adadad", /* white */
|
||||
"black",
|
||||
"red3",
|
||||
"green3",
|
||||
"yellow3",
|
||||
"blue2",
|
||||
"magenta3",
|
||||
"cyan3",
|
||||
"gray90",
|
||||
|
||||
/* 8 bright colors */
|
||||
[8] = "#424242", /* black */
|
||||
[9] = "#cf6a4c", /* red */
|
||||
[10] = "#99ad6a", /* green */
|
||||
[11] = "#d8ad4c", /* yellow */
|
||||
[12] = "#597bc5", /* blue */
|
||||
[13] = "#a037b0", /* magenta */
|
||||
[14] = "#71b9f8", /* cyan */
|
||||
[15] = "#ffffff", /* white */
|
||||
"gray50",
|
||||
"red",
|
||||
"green",
|
||||
"yellow",
|
||||
"#5c5cff",
|
||||
"magenta",
|
||||
"cyan",
|
||||
"white",
|
||||
|
||||
/* special colors */
|
||||
[256] = "#151515", /* background */
|
||||
[257] = "#eaeaea", /* foreground */
|
||||
[255] = 0,
|
||||
|
||||
/* more colors can be added after 255 to use with DefaultXX */
|
||||
"#cccccc",
|
||||
@@ -129,21 +127,13 @@ static const char *colorname[] = {
|
||||
|
||||
/*
|
||||
* Default colors (colorname index)
|
||||
* foreground, background, cursor
|
||||
* foreground, background, cursor, reverse cursor
|
||||
*/
|
||||
unsigned int defaultfg = 257;
|
||||
unsigned int defaultbg = 256;
|
||||
unsigned int defaultcs = 257;
|
||||
unsigned int defaultfg = 258;
|
||||
unsigned int defaultbg = 259;
|
||||
unsigned int defaultcs = 256;
|
||||
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.
|
||||
*/
|
||||
unsigned int defaultitalic = 7;
|
||||
unsigned int defaultunderline = 7;
|
||||
|
||||
/*
|
||||
* Default shape of cursor
|
||||
* 2: Block ("█")
|
||||
@@ -180,6 +170,42 @@ static unsigned int defaultattr = 11;
|
||||
*/
|
||||
static uint forcemousemod = ShiftMask;
|
||||
|
||||
/*
|
||||
* Xresources preferences to load at startup
|
||||
*/
|
||||
ResourcePref resources[] = {
|
||||
{ "font", STRING, &font },
|
||||
{ "color0", STRING, &colorname[0] },
|
||||
{ "color1", STRING, &colorname[1] },
|
||||
{ "color2", STRING, &colorname[2] },
|
||||
{ "color3", STRING, &colorname[3] },
|
||||
{ "color4", STRING, &colorname[4] },
|
||||
{ "color5", STRING, &colorname[5] },
|
||||
{ "color6", STRING, &colorname[6] },
|
||||
{ "color7", STRING, &colorname[7] },
|
||||
{ "color8", STRING, &colorname[8] },
|
||||
{ "color9", STRING, &colorname[9] },
|
||||
{ "color10", STRING, &colorname[10] },
|
||||
{ "color11", STRING, &colorname[11] },
|
||||
{ "color12", STRING, &colorname[12] },
|
||||
{ "color13", STRING, &colorname[13] },
|
||||
{ "color14", STRING, &colorname[14] },
|
||||
{ "color15", STRING, &colorname[15] },
|
||||
{ "background", STRING, &colorname[259] },
|
||||
{ "foreground", STRING, &colorname[258] },
|
||||
{ "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 },
|
||||
{ "borderpx", INTEGER, &borderpx },
|
||||
{ "cwscale", FLOAT, &cwscale },
|
||||
{ "chscale", FLOAT, &chscale },
|
||||
};
|
||||
|
||||
/*
|
||||
* Internal mouse shortcuts.
|
||||
* Beware that overloading Button1 will disable the selection.
|
||||
@@ -203,14 +229,16 @@ static Shortcut shortcuts[] = {
|
||||
{ ControlMask, XK_Print, toggleprinter, {.i = 0} },
|
||||
{ ShiftMask, XK_Print, printscreen, {.i = 0} },
|
||||
{ XK_ANY_MOD, XK_Print, printsel, {.i = 0} },
|
||||
{ MODKEY, XK_Prior, zoom, {.f = +2} },
|
||||
{ MODKEY, XK_Next, zoom, {.f = -2} },
|
||||
{ MODKEY, XK_Home, zoomreset, {.f = 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} },
|
||||
{ ShiftMask, XK_Page_Up, kscrollup, {.f = -0.1} },
|
||||
{ ShiftMask, XK_Page_Down, kscrolldown, {.f = -0.1} },
|
||||
};
|
||||
|
||||
/*
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# st version
|
||||
VERSION = 0.8.5
|
||||
VERSION = 0.9.3
|
||||
|
||||
# Customize below to fit your system
|
||||
|
||||
|
||||
@@ -1,81 +0,0 @@
|
||||
diff '--color=auto' -up ../st/config.def.h ./config.def.h
|
||||
--- ../st/config.def.h 2022-03-09 08:28:40.186246176 -0300
|
||||
+++ ./config.def.h 2022-03-09 08:26:03.194323581 -0300
|
||||
@@ -95,27 +95,29 @@ unsigned int tabspaces = 8;
|
||||
|
||||
/* Terminal colors (16 first used in escape sequence) */
|
||||
static const char *colorname[] = {
|
||||
- /* 8 normal colors */
|
||||
- "black",
|
||||
- "red3",
|
||||
- "green3",
|
||||
- "yellow3",
|
||||
- "blue2",
|
||||
- "magenta3",
|
||||
- "cyan3",
|
||||
- "gray90",
|
||||
-
|
||||
- /* 8 bright colors */
|
||||
- "gray50",
|
||||
- "red",
|
||||
- "green",
|
||||
- "yellow",
|
||||
- "#5c5cff",
|
||||
- "magenta",
|
||||
- "cyan",
|
||||
- "white",
|
||||
-
|
||||
- [255] = 0,
|
||||
+ /* 8 normal colors */
|
||||
+ [0] = "#000000", /* black */
|
||||
+ [1] = "#ff5555", /* red */
|
||||
+ [2] = "#50fa7b", /* green */
|
||||
+ [3] = "#f1fa8c", /* yellow */
|
||||
+ [4] = "#bd93f9", /* blue */
|
||||
+ [5] = "#ff79c6", /* magenta */
|
||||
+ [6] = "#8be9fd", /* cyan */
|
||||
+ [7] = "#bbbbbb", /* white */
|
||||
+
|
||||
+ /* 8 bright colors */
|
||||
+ [8] = "#44475a", /* black */
|
||||
+ [9] = "#ff5555", /* red */
|
||||
+ [10] = "#50fa7b", /* green */
|
||||
+ [11] = "#f1fa8c", /* yellow */
|
||||
+ [12] = "#bd93f9", /* blue */
|
||||
+ [13] = "#ff79c6", /* magenta */
|
||||
+ [14] = "#8be9fd", /* cyan */
|
||||
+ [15] = "#ffffff", /* white */
|
||||
+
|
||||
+ /* special colors */
|
||||
+ [256] = "#282a36", /* background */
|
||||
+ [257] = "#f8f8f2", /* foreground */
|
||||
|
||||
/* more colors can be added after 255 to use with DefaultXX */
|
||||
"#cccccc",
|
||||
@@ -127,14 +129,22 @@ static const char *colorname[] = {
|
||||
|
||||
/*
|
||||
* Default colors (colorname index)
|
||||
- * foreground, background, cursor, reverse cursor
|
||||
+ * foreground, background, cursor
|
||||
*/
|
||||
-unsigned int defaultfg = 258;
|
||||
-unsigned int defaultbg = 259;
|
||||
-unsigned int defaultcs = 256;
|
||||
+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.
|
||||
+ */
|
||||
+unsigned int defaultitalic = 7;
|
||||
+unsigned int defaultunderline = 7;
|
||||
+
|
||||
+/*
|
||||
* Default shape of cursor
|
||||
* 2: Block ("â–ˆ")
|
||||
* 4: Underline ("_")
|
||||
52
patches/st-scrollback-float-0.9.2.diff
Normal file
52
patches/st-scrollback-float-0.9.2.diff
Normal file
@@ -0,0 +1,52 @@
|
||||
diff --git a/config.def.h b/config.def.h
|
||||
index 8b25d40..6769f99 100644
|
||||
--- a/config.def.h
|
||||
+++ b/config.def.h
|
||||
@@ -201,8 +201,8 @@ static Shortcut shortcuts[] = {
|
||||
{ TERMMOD, XK_Y, selpaste, {.i = 0} },
|
||||
{ ShiftMask, XK_Insert, selpaste, {.i = 0} },
|
||||
{ TERMMOD, XK_Num_Lock, numlock, {.i = 0} },
|
||||
- { ShiftMask, XK_Page_Up, kscrollup, {.i = -1} },
|
||||
- { ShiftMask, XK_Page_Down, kscrolldown, {.i = -1} },
|
||||
+ { ShiftMask, XK_Page_Up, kscrollup, {.f = -0.1} },
|
||||
+ { ShiftMask, XK_Page_Down, kscrolldown, {.f = -0.1} },
|
||||
};
|
||||
|
||||
/*
|
||||
diff --git a/st.c b/st.c
|
||||
index a3b3c9d..5a93594 100644
|
||||
--- a/st.c
|
||||
+++ b/st.c
|
||||
@@ -1087,14 +1087,14 @@ tswapscreen(void)
|
||||
void
|
||||
kscrollup(const Arg *a)
|
||||
{
|
||||
- int n = a->i;
|
||||
+ float n = a->f;
|
||||
|
||||
if (IS_SET(MODE_ALTSCREEN))
|
||||
return;
|
||||
|
||||
- if (n < 0) n = (-n) * term.row;
|
||||
+ if (n < 0) n = MAX((-n) * term.row, 1);
|
||||
if (n > TSCREEN.size - term.row - TSCREEN.off) n = TSCREEN.size - term.row - TSCREEN.off;
|
||||
- while (!TLINE(-n)) --n;
|
||||
+ while (!TLINE((int)-n)) --n;
|
||||
TSCREEN.off += n;
|
||||
selscroll(0, n);
|
||||
tfulldirt();
|
||||
@@ -1104,12 +1104,12 @@ void
|
||||
kscrolldown(const Arg *a)
|
||||
{
|
||||
|
||||
- int n = a->i;
|
||||
+ float n = a->f;
|
||||
|
||||
if (IS_SET(MODE_ALTSCREEN))
|
||||
return;
|
||||
|
||||
- if (n < 0) n = (-n) * term.row;
|
||||
+ if (n < 0) n = MAX((-n) * term.row, 1);
|
||||
if (n > TSCREEN.off) n = TSCREEN.off;
|
||||
TSCREEN.off -= n;
|
||||
selscroll(0, -n);
|
||||
730
patches/st-scrollback-ringbuffer-0.9.2.diff
Executable file
730
patches/st-scrollback-ringbuffer-0.9.2.diff
Executable file
@@ -0,0 +1,730 @@
|
||||
commit 0663bdf11a409961da5b1120741a69814da8ce65
|
||||
Author: Timo RГ¶hling <timo@gaussglocke.de>
|
||||
Date: Tue Nov 23 19:45:33 2021 +0100
|
||||
|
||||
Terminal scrollback with ring buffer
|
||||
|
||||
This patch adds a ring buffer for scrollback to the terminal. The
|
||||
advantage of using a ring buffer is that the common case, scrolling with
|
||||
no static screen content, can be achieved very efficiently by
|
||||
incrementing and decrementing the starting line (modulo buffer size).
|
||||
|
||||
The scrollback buffer is limited to HISTSIZE lines in order to bound
|
||||
memory usage. As the lines are allocated on demand, it is possible to
|
||||
implement unlimited scrollback with few changes. If the terminal is
|
||||
reset, the scroll back buffer is reset, too.
|
||||
|
||||
diff --git a/config.def.h b/config.def.h
|
||||
index 2cd740a..8b25d40 100644
|
||||
--- a/config.def.h
|
||||
+++ b/config.def.h
|
||||
@@ -201,6 +201,8 @@ static Shortcut shortcuts[] = {
|
||||
{ TERMMOD, XK_Y, selpaste, {.i = 0} },
|
||||
{ ShiftMask, XK_Insert, selpaste, {.i = 0} },
|
||||
{ TERMMOD, XK_Num_Lock, numlock, {.i = 0} },
|
||||
+ { ShiftMask, XK_Page_Up, kscrollup, {.i = -1} },
|
||||
+ { ShiftMask, XK_Page_Down, kscrolldown, {.i = -1} },
|
||||
};
|
||||
|
||||
/*
|
||||
diff --git a/st.c b/st.c
|
||||
index b9f66e7..d9b163e 100644
|
||||
--- a/st.c
|
||||
+++ b/st.c
|
||||
@@ -43,6 +43,10 @@
|
||||
#define ISCONTROL(c) (ISCONTROLC0(c) || ISCONTROLC1(c))
|
||||
#define ISDELIM(u) (u && wcschr(worddelimiters, u))
|
||||
|
||||
+#define TSCREEN term.screen[IS_SET(MODE_ALTSCREEN)]
|
||||
+#define TLINEOFFSET(y) (((y) + TSCREEN.cur - TSCREEN.off + TSCREEN.size) % TSCREEN.size)
|
||||
+#define TLINE(y) (TSCREEN.buffer[TLINEOFFSET(y)])
|
||||
+
|
||||
enum term_mode {
|
||||
MODE_WRAP = 1 << 0,
|
||||
MODE_INSERT = 1 << 1,
|
||||
@@ -109,12 +113,21 @@ typedef struct {
|
||||
int alt;
|
||||
} Selection;
|
||||
|
||||
+/* Screen lines */
|
||||
+typedef struct {
|
||||
+ Line* buffer; /* ring buffer */
|
||||
+ int size; /* size of buffer */
|
||||
+ int cur; /* start of active screen */
|
||||
+ int off; /* scrollback line offset */
|
||||
+ TCursor sc; /* saved cursor */
|
||||
+} LineBuffer;
|
||||
+
|
||||
/* Internal representation of the screen */
|
||||
typedef struct {
|
||||
int row; /* nb row */
|
||||
int col; /* nb col */
|
||||
- Line *line; /* screen */
|
||||
- Line *alt; /* alternate screen */
|
||||
+ LineBuffer screen[2]; /* screen and alternate screen */
|
||||
+ int linelen; /* allocated line length */
|
||||
int *dirty; /* dirtyness of lines */
|
||||
TCursor c; /* cursor */
|
||||
int ocx; /* old cursor col */
|
||||
@@ -203,6 +216,8 @@ static void tdeftran(char);
|
||||
static void tstrsequence(uchar);
|
||||
|
||||
static void drawregion(int, int, int, int);
|
||||
+static void clearline(Line, Glyph, int, int);
|
||||
+static Line ensureline(Line);
|
||||
|
||||
static void selnormalize(void);
|
||||
static void selscroll(int, int);
|
||||
@@ -408,11 +423,12 @@ int
|
||||
tlinelen(int y)
|
||||
{
|
||||
int i = term.col;
|
||||
+ Line line = TLINE(y);
|
||||
|
||||
- if (term.line[y][i - 1].mode & ATTR_WRAP)
|
||||
+ if (line[i - 1].mode & ATTR_WRAP)
|
||||
return i;
|
||||
|
||||
- while (i > 0 && term.line[y][i - 1].u == ' ')
|
||||
+ while (i > 0 && line[i - 1].u == ' ')
|
||||
--i;
|
||||
|
||||
return i;
|
||||
@@ -521,7 +537,7 @@ selsnap(int *x, int *y, int direction)
|
||||
* Snap around if the word wraps around at the end or
|
||||
* beginning of a line.
|
||||
*/
|
||||
- prevgp = &term.line[*y][*x];
|
||||
+ prevgp = &TLINE(*y)[*x];
|
||||
prevdelim = ISDELIM(prevgp->u);
|
||||
for (;;) {
|
||||
newx = *x + direction;
|
||||
@@ -536,14 +552,14 @@ selsnap(int *x, int *y, int direction)
|
||||
yt = *y, xt = *x;
|
||||
else
|
||||
yt = newy, xt = newx;
|
||||
- if (!(term.line[yt][xt].mode & ATTR_WRAP))
|
||||
+ if (!(TLINE(yt)[xt].mode & ATTR_WRAP))
|
||||
break;
|
||||
}
|
||||
|
||||
if (newx >= tlinelen(newy))
|
||||
break;
|
||||
|
||||
- gp = &term.line[newy][newx];
|
||||
+ gp = &TLINE(newy)[newx];
|
||||
delim = ISDELIM(gp->u);
|
||||
if (!(gp->mode & ATTR_WDUMMY) && (delim != prevdelim
|
||||
|| (delim && gp->u != prevgp->u)))
|
||||
@@ -564,14 +580,14 @@ selsnap(int *x, int *y, int direction)
|
||||
*x = (direction < 0) ? 0 : term.col - 1;
|
||||
if (direction < 0) {
|
||||
for (; *y > 0; *y += direction) {
|
||||
- if (!(term.line[*y-1][term.col-1].mode
|
||||
+ if (!(TLINE(*y-1)[term.col-1].mode
|
||||
& ATTR_WRAP)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (direction > 0) {
|
||||
for (; *y < term.row-1; *y += direction) {
|
||||
- if (!(term.line[*y][term.col-1].mode
|
||||
+ if (!(TLINE(*y)[term.col-1].mode
|
||||
& ATTR_WRAP)) {
|
||||
break;
|
||||
}
|
||||
@@ -602,13 +618,13 @@ getsel(void)
|
||||
}
|
||||
|
||||
if (sel.type == SEL_RECTANGULAR) {
|
||||
- gp = &term.line[y][sel.nb.x];
|
||||
+ gp = &TLINE(y)[sel.nb.x];
|
||||
lastx = sel.ne.x;
|
||||
} else {
|
||||
- gp = &term.line[y][sel.nb.y == y ? sel.nb.x : 0];
|
||||
+ gp = &TLINE(y)[sel.nb.y == y ? sel.nb.x : 0];
|
||||
lastx = (sel.ne.y == y) ? sel.ne.x : term.col-1;
|
||||
}
|
||||
- last = &term.line[y][MIN(lastx, linelen-1)];
|
||||
+ last = &TLINE(y)[MIN(lastx, linelen-1)];
|
||||
while (last >= gp && last->u == ' ')
|
||||
--last;
|
||||
|
||||
@@ -949,12 +965,15 @@ int
|
||||
tattrset(int attr)
|
||||
{
|
||||
int i, j;
|
||||
+ int y = TLINEOFFSET(0);
|
||||
|
||||
for (i = 0; i < term.row-1; i++) {
|
||||
+ Line line = TSCREEN.buffer[y];
|
||||
for (j = 0; j < term.col-1; j++) {
|
||||
- if (term.line[i][j].mode & attr)
|
||||
+ if (line[j].mode & attr)
|
||||
return 1;
|
||||
}
|
||||
+ y = (y+1) % TSCREEN.size;
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -976,14 +995,17 @@ void
|
||||
tsetdirtattr(int attr)
|
||||
{
|
||||
int i, j;
|
||||
+ int y = TLINEOFFSET(0);
|
||||
|
||||
for (i = 0; i < term.row-1; i++) {
|
||||
+ Line line = TSCREEN.buffer[y];
|
||||
for (j = 0; j < term.col-1; j++) {
|
||||
- if (term.line[i][j].mode & attr) {
|
||||
+ if (line[j].mode & attr) {
|
||||
tsetdirt(i, i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
+ y = (y+1) % TSCREEN.size;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -996,27 +1018,19 @@ tfulldirt(void)
|
||||
void
|
||||
tcursor(int mode)
|
||||
{
|
||||
- static TCursor c[2];
|
||||
- int alt = IS_SET(MODE_ALTSCREEN);
|
||||
-
|
||||
if (mode == CURSOR_SAVE) {
|
||||
- c[alt] = term.c;
|
||||
+ TSCREEN.sc = term.c;
|
||||
} else if (mode == CURSOR_LOAD) {
|
||||
- term.c = c[alt];
|
||||
- tmoveto(c[alt].x, c[alt].y);
|
||||
+ term.c = TSCREEN.sc;
|
||||
+ tmoveto(term.c.x, term.c.y);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
treset(void)
|
||||
{
|
||||
- uint i;
|
||||
-
|
||||
- term.c = (TCursor){{
|
||||
- .mode = ATTR_NULL,
|
||||
- .fg = defaultfg,
|
||||
- .bg = defaultbg
|
||||
- }, .x = 0, .y = 0, .state = CURSOR_DEFAULT};
|
||||
+ int i, j;
|
||||
+ Glyph g = (Glyph){ .fg = defaultfg, .bg = defaultbg};
|
||||
|
||||
memset(term.tabs, 0, term.col * sizeof(*term.tabs));
|
||||
for (i = tabspaces; i < term.col; i += tabspaces)
|
||||
@@ -1028,17 +1042,37 @@ treset(void)
|
||||
term.charset = 0;
|
||||
|
||||
for (i = 0; i < 2; i++) {
|
||||
- tmoveto(0, 0);
|
||||
- tcursor(CURSOR_SAVE);
|
||||
- tclearregion(0, 0, term.col-1, term.row-1);
|
||||
- tswapscreen();
|
||||
+ term.screen[i].sc = (TCursor){{
|
||||
+ .fg = defaultfg,
|
||||
+ .bg = defaultbg
|
||||
+ }};
|
||||
+ term.screen[i].cur = 0;
|
||||
+ term.screen[i].off = 0;
|
||||
+ for (j = 0; j < term.row; ++j) {
|
||||
+ if (term.col != term.linelen)
|
||||
+ term.screen[i].buffer[j] = xrealloc(term.screen[i].buffer[j], term.col * sizeof(Glyph));
|
||||
+ clearline(term.screen[i].buffer[j], g, 0, term.col);
|
||||
+ }
|
||||
+ for (j = term.row; j < term.screen[i].size; ++j) {
|
||||
+ free(term.screen[i].buffer[j]);
|
||||
+ term.screen[i].buffer[j] = NULL;
|
||||
+ }
|
||||
}
|
||||
+ tcursor(CURSOR_LOAD);
|
||||
+ term.linelen = term.col;
|
||||
+ tfulldirt();
|
||||
}
|
||||
|
||||
void
|
||||
tnew(int col, int row)
|
||||
{
|
||||
- term = (Term){ .c = { .attr = { .fg = defaultfg, .bg = defaultbg } } };
|
||||
+ int i;
|
||||
+ term = (Term){};
|
||||
+ term.screen[0].buffer = xmalloc(HISTSIZE * sizeof(Line));
|
||||
+ term.screen[0].size = HISTSIZE;
|
||||
+ term.screen[1].buffer = NULL;
|
||||
+ for (i = 0; i < HISTSIZE; ++i) term.screen[0].buffer[i] = NULL;
|
||||
+
|
||||
tresize(col, row);
|
||||
treset();
|
||||
}
|
||||
@@ -1046,14 +1080,42 @@ tnew(int col, int row)
|
||||
void
|
||||
tswapscreen(void)
|
||||
{
|
||||
- Line *tmp = term.line;
|
||||
-
|
||||
- term.line = term.alt;
|
||||
- term.alt = tmp;
|
||||
term.mode ^= MODE_ALTSCREEN;
|
||||
tfulldirt();
|
||||
}
|
||||
|
||||
+void
|
||||
+kscrollup(const Arg *a)
|
||||
+{
|
||||
+ int n = a->i;
|
||||
+
|
||||
+ if (IS_SET(MODE_ALTSCREEN))
|
||||
+ return;
|
||||
+
|
||||
+ if (n < 0) n = (-n) * term.row;
|
||||
+ if (n > TSCREEN.size - term.row - TSCREEN.off) n = TSCREEN.size - term.row - TSCREEN.off;
|
||||
+ while (!TLINE(-n)) --n;
|
||||
+ TSCREEN.off += n;
|
||||
+ selscroll(0, n);
|
||||
+ tfulldirt();
|
||||
+}
|
||||
+
|
||||
+void
|
||||
+kscrolldown(const Arg *a)
|
||||
+{
|
||||
+
|
||||
+ int n = a->i;
|
||||
+
|
||||
+ if (IS_SET(MODE_ALTSCREEN))
|
||||
+ return;
|
||||
+
|
||||
+ if (n < 0) n = (-n) * term.row;
|
||||
+ if (n > TSCREEN.off) n = TSCREEN.off;
|
||||
+ TSCREEN.off -= n;
|
||||
+ selscroll(0, -n);
|
||||
+ tfulldirt();
|
||||
+}
|
||||
+
|
||||
void
|
||||
tscrolldown(int orig, int n)
|
||||
{
|
||||
@@ -1062,15 +1124,29 @@ tscrolldown(int orig, int n)
|
||||
|
||||
LIMIT(n, 0, term.bot-orig+1);
|
||||
|
||||
- tsetdirt(orig, term.bot-n);
|
||||
- tclearregion(0, term.bot-n+1, term.col-1, term.bot);
|
||||
+ /* Ensure that lines are allocated */
|
||||
+ for (i = -n; i < 0; i++) {
|
||||
+ TLINE(i) = ensureline(TLINE(i));
|
||||
+ }
|
||||
|
||||
- for (i = term.bot; i >= orig+n; i--) {
|
||||
- temp = term.line[i];
|
||||
- term.line[i] = term.line[i-n];
|
||||
- term.line[i-n] = temp;
|
||||
+ /* Shift non-scrolling areas in ring buffer */
|
||||
+ for (i = term.bot+1; i < term.row; i++) {
|
||||
+ temp = TLINE(i);
|
||||
+ TLINE(i) = TLINE(i-n);
|
||||
+ TLINE(i-n) = temp;
|
||||
+ }
|
||||
+ for (i = 0; i < orig; i++) {
|
||||
+ temp = TLINE(i);
|
||||
+ TLINE(i) = TLINE(i-n);
|
||||
+ TLINE(i-n) = temp;
|
||||
}
|
||||
|
||||
+ /* Scroll buffer */
|
||||
+ TSCREEN.cur = (TSCREEN.cur + TSCREEN.size - n) % TSCREEN.size;
|
||||
+ /* Clear lines that have entered the view */
|
||||
+ tclearregion(0, orig, term.linelen-1, orig+n-1);
|
||||
+ /* Redraw portion of the screen that has scrolled */
|
||||
+ tsetdirt(orig+n-1, term.bot);
|
||||
selscroll(orig, n);
|
||||
}
|
||||
|
||||
@@ -1082,15 +1158,29 @@ tscrollup(int orig, int n)
|
||||
|
||||
LIMIT(n, 0, term.bot-orig+1);
|
||||
|
||||
- tclearregion(0, orig, term.col-1, orig+n-1);
|
||||
- tsetdirt(orig+n, term.bot);
|
||||
+ /* Ensure that lines are allocated */
|
||||
+ for (i = term.row; i < term.row + n; i++) {
|
||||
+ TLINE(i) = ensureline(TLINE(i));
|
||||
+ }
|
||||
|
||||
- for (i = orig; i <= term.bot-n; i++) {
|
||||
- temp = term.line[i];
|
||||
- term.line[i] = term.line[i+n];
|
||||
- term.line[i+n] = temp;
|
||||
+ /* Shift non-scrolling areas in ring buffer */
|
||||
+ for (i = orig-1; i >= 0; i--) {
|
||||
+ temp = TLINE(i);
|
||||
+ TLINE(i) = TLINE(i+n);
|
||||
+ TLINE(i+n) = temp;
|
||||
+ }
|
||||
+ for (i = term.row-1; i >term.bot; i--) {
|
||||
+ temp = TLINE(i);
|
||||
+ TLINE(i) = TLINE(i+n);
|
||||
+ TLINE(i+n) = temp;
|
||||
}
|
||||
|
||||
+ /* Scroll buffer */
|
||||
+ TSCREEN.cur = (TSCREEN.cur + n) % TSCREEN.size;
|
||||
+ /* Clear lines that have entered the view */
|
||||
+ tclearregion(0, term.bot-n+1, term.linelen-1, term.bot);
|
||||
+ /* Redraw portion of the screen that has scrolled */
|
||||
+ tsetdirt(orig, term.bot-n+1);
|
||||
selscroll(orig, -n);
|
||||
}
|
||||
|
||||
@@ -1194,6 +1284,7 @@ tsetchar(Rune u, const Glyph *attr, int x, int y)
|
||||
"⎻", "─", "⎼", "⎽", "├", "┤", "┴", "┬", /* p - w */
|
||||
"│", "≤", "≥", "π", "≠", "£", "·", /* x - ~ */
|
||||
};
|
||||
+ Line line = TLINE(y);
|
||||
|
||||
/*
|
||||
* The table is proudly stolen from rxvt.
|
||||
@@ -1202,25 +1293,25 @@ tsetchar(Rune u, const Glyph *attr, int x, int y)
|
||||
BETWEEN(u, 0x41, 0x7e) && vt100_0[u - 0x41])
|
||||
utf8decode(vt100_0[u - 0x41], &u, UTF_SIZ);
|
||||
|
||||
- if (term.line[y][x].mode & ATTR_WIDE) {
|
||||
+ if (line[x].mode & ATTR_WIDE) {
|
||||
if (x+1 < term.col) {
|
||||
- term.line[y][x+1].u = ' ';
|
||||
- term.line[y][x+1].mode &= ~ATTR_WDUMMY;
|
||||
+ line[x+1].u = ' ';
|
||||
+ line[x+1].mode &= ~ATTR_WDUMMY;
|
||||
}
|
||||
- } else if (term.line[y][x].mode & ATTR_WDUMMY) {
|
||||
- term.line[y][x-1].u = ' ';
|
||||
- term.line[y][x-1].mode &= ~ATTR_WIDE;
|
||||
+ } else if (line[x].mode & ATTR_WDUMMY) {
|
||||
+ line[x-1].u = ' ';
|
||||
+ line[x-1].mode &= ~ATTR_WIDE;
|
||||
}
|
||||
|
||||
term.dirty[y] = 1;
|
||||
- term.line[y][x] = *attr;
|
||||
- term.line[y][x].u = u;
|
||||
+ line[x] = *attr;
|
||||
+ line[x].u = u;
|
||||
}
|
||||
|
||||
void
|
||||
tclearregion(int x1, int y1, int x2, int y2)
|
||||
{
|
||||
- int x, y, temp;
|
||||
+ int x, y, L, S, temp;
|
||||
Glyph *gp;
|
||||
|
||||
if (x1 > x2)
|
||||
@@ -1228,15 +1319,16 @@ tclearregion(int x1, int y1, int x2, int y2)
|
||||
if (y1 > y2)
|
||||
temp = y1, y1 = y2, y2 = temp;
|
||||
|
||||
- LIMIT(x1, 0, term.col-1);
|
||||
- LIMIT(x2, 0, term.col-1);
|
||||
+ LIMIT(x1, 0, term.linelen-1);
|
||||
+ LIMIT(x2, 0, term.linelen-1);
|
||||
LIMIT(y1, 0, term.row-1);
|
||||
LIMIT(y2, 0, term.row-1);
|
||||
|
||||
+ L = TLINEOFFSET(y1);
|
||||
for (y = y1; y <= y2; y++) {
|
||||
term.dirty[y] = 1;
|
||||
for (x = x1; x <= x2; x++) {
|
||||
- gp = &term.line[y][x];
|
||||
+ gp = &TSCREEN.buffer[L][x];
|
||||
if (selected(x, y))
|
||||
selclear();
|
||||
gp->fg = term.c.attr.fg;
|
||||
@@ -1244,6 +1336,7 @@ tclearregion(int x1, int y1, int x2, int y2)
|
||||
gp->mode = 0;
|
||||
gp->u = ' ';
|
||||
}
|
||||
+ L = (L + 1) % TSCREEN.size;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1258,7 +1351,7 @@ tdeletechar(int n)
|
||||
dst = term.c.x;
|
||||
src = term.c.x + n;
|
||||
size = term.col - src;
|
||||
- line = term.line[term.c.y];
|
||||
+ line = TLINE(term.c.y);
|
||||
|
||||
memmove(&line[dst], &line[src], size * sizeof(Glyph));
|
||||
tclearregion(term.col-n, term.c.y, term.col-1, term.c.y);
|
||||
@@ -1275,7 +1368,7 @@ tinsertblank(int n)
|
||||
dst = term.c.x + n;
|
||||
src = term.c.x;
|
||||
size = term.col - dst;
|
||||
- line = term.line[term.c.y];
|
||||
+ line = TLINE(term.c.y);
|
||||
|
||||
memmove(&line[dst], &line[src], size * sizeof(Glyph));
|
||||
tclearregion(src, term.c.y, dst - 1, term.c.y);
|
||||
@@ -2079,7 +2172,7 @@ tdumpline(int n)
|
||||
char buf[UTF_SIZ];
|
||||
const Glyph *bp, *end;
|
||||
|
||||
- bp = &term.line[n][0];
|
||||
+ bp = &TLINE(n)[0];
|
||||
end = &bp[MIN(tlinelen(n), term.col) - 1];
|
||||
if (bp != end || bp->u != ' ') {
|
||||
for ( ; bp <= end; ++bp)
|
||||
@@ -2466,11 +2559,11 @@ check_control_code:
|
||||
if (selected(term.c.x, term.c.y))
|
||||
selclear();
|
||||
|
||||
- gp = &term.line[term.c.y][term.c.x];
|
||||
+ gp = &TLINE(term.c.y)[term.c.x];
|
||||
if (IS_SET(MODE_WRAP) && (term.c.state & CURSOR_WRAPNEXT)) {
|
||||
gp->mode |= ATTR_WRAP;
|
||||
tnewline(1);
|
||||
- gp = &term.line[term.c.y][term.c.x];
|
||||
+ gp = &TLINE(term.c.y)[term.c.x];
|
||||
}
|
||||
|
||||
if (IS_SET(MODE_INSERT) && term.c.x+width < term.col) {
|
||||
@@ -2483,7 +2576,7 @@ check_control_code:
|
||||
tnewline(1);
|
||||
else
|
||||
tmoveto(term.col - width, term.c.y);
|
||||
- gp = &term.line[term.c.y][term.c.x];
|
||||
+ gp = &TLINE(term.c.y)[term.c.x];
|
||||
}
|
||||
|
||||
tsetchar(u, &term.c.attr, term.c.x, term.c.y);
|
||||
@@ -2514,6 +2607,11 @@ twrite(const char *buf, int buflen, int show_ctrl)
|
||||
Rune u;
|
||||
int n;
|
||||
|
||||
+ if (TSCREEN.off) {
|
||||
+ TSCREEN.off = 0;
|
||||
+ tfulldirt();
|
||||
+ }
|
||||
+
|
||||
for (n = 0; n < buflen; n += charsize) {
|
||||
if (IS_SET(MODE_UTF8)) {
|
||||
/* process a complete utf8 char */
|
||||
@@ -2540,56 +2638,85 @@ twrite(const char *buf, int buflen, int show_ctrl)
|
||||
}
|
||||
|
||||
void
|
||||
-tresize(int col, int row)
|
||||
+clearline(Line line, Glyph g, int x, int xend)
|
||||
{
|
||||
int i;
|
||||
+ g.mode = 0;
|
||||
+ g.u = ' ';
|
||||
+ for (i = x; i < xend; ++i) {
|
||||
+ line[i] = g;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+Line
|
||||
+ensureline(Line line)
|
||||
+{
|
||||
+ if (!line) {
|
||||
+ line = xmalloc(term.linelen * sizeof(Glyph));
|
||||
+ }
|
||||
+ return line;
|
||||
+}
|
||||
+
|
||||
+void
|
||||
+tresize(int col, int row)
|
||||
+{
|
||||
+ int i, j;
|
||||
int minrow = MIN(row, term.row);
|
||||
int mincol = MIN(col, term.col);
|
||||
+ int linelen = MAX(col, term.linelen);
|
||||
int *bp;
|
||||
- TCursor c;
|
||||
|
||||
- if (col < 1 || row < 1) {
|
||||
+ if (col < 1 || row < 1 || row > HISTSIZE) {
|
||||
fprintf(stderr,
|
||||
"tresize: error resizing to %dx%d\n", col, row);
|
||||
return;
|
||||
}
|
||||
|
||||
- /*
|
||||
- * slide screen to keep cursor where we expect it -
|
||||
- * tscrollup would work here, but we can optimize to
|
||||
- * memmove because we're freeing the earlier lines
|
||||
- */
|
||||
- for (i = 0; i <= term.c.y - row; i++) {
|
||||
- free(term.line[i]);
|
||||
- free(term.alt[i]);
|
||||
+ /* Shift buffer to keep the cursor where we expect it */
|
||||
+ if (row <= term.c.y) {
|
||||
+ term.screen[0].cur = (term.screen[0].cur - row + term.c.y + 1) % term.screen[0].size;
|
||||
+ }
|
||||
+
|
||||
+ /* Resize and clear line buffers as needed */
|
||||
+ if (linelen > term.linelen) {
|
||||
+ for (i = 0; i < term.screen[0].size; ++i) {
|
||||
+ if (term.screen[0].buffer[i]) {
|
||||
+ term.screen[0].buffer[i] = xrealloc(term.screen[0].buffer[i], linelen * sizeof(Glyph));
|
||||
+ clearline(term.screen[0].buffer[i], term.c.attr, term.linelen, linelen);
|
||||
+ }
|
||||
+ }
|
||||
+ for (i = 0; i < minrow; ++i) {
|
||||
+ term.screen[1].buffer[i] = xrealloc(term.screen[1].buffer[i], linelen * sizeof(Glyph));
|
||||
+ clearline(term.screen[1].buffer[i], term.c.attr, term.linelen, linelen);
|
||||
+ }
|
||||
}
|
||||
- /* ensure that both src and dst are not NULL */
|
||||
- if (i > 0) {
|
||||
- memmove(term.line, term.line + i, row * sizeof(Line));
|
||||
- memmove(term.alt, term.alt + i, row * sizeof(Line));
|
||||
+ /* Allocate all visible lines for regular line buffer */
|
||||
+ for (j = term.screen[0].cur, i = 0; i < row; ++i, j = (j + 1) % term.screen[0].size)
|
||||
+ {
|
||||
+ if (!term.screen[0].buffer[j]) {
|
||||
+ term.screen[0].buffer[j] = xmalloc(linelen * sizeof(Glyph));
|
||||
+ }
|
||||
+ if (i >= term.row) {
|
||||
+ clearline(term.screen[0].buffer[j], term.c.attr, 0, linelen);
|
||||
+ }
|
||||
}
|
||||
- for (i += row; i < term.row; i++) {
|
||||
- free(term.line[i]);
|
||||
- free(term.alt[i]);
|
||||
+ /* Resize alt screen */
|
||||
+ term.screen[1].cur = 0;
|
||||
+ term.screen[1].size = row;
|
||||
+ for (i = row; i < term.row; ++i) {
|
||||
+ free(term.screen[1].buffer[i]);
|
||||
+ }
|
||||
+ term.screen[1].buffer = xrealloc(term.screen[1].buffer, row * sizeof(Line));
|
||||
+ for (i = term.row; i < row; ++i) {
|
||||
+ term.screen[1].buffer[i] = xmalloc(linelen * sizeof(Glyph));
|
||||
+ clearline(term.screen[1].buffer[i], term.c.attr, 0, linelen);
|
||||
}
|
||||
|
||||
/* resize to new height */
|
||||
- term.line = xrealloc(term.line, row * sizeof(Line));
|
||||
- term.alt = xrealloc(term.alt, row * sizeof(Line));
|
||||
term.dirty = xrealloc(term.dirty, row * sizeof(*term.dirty));
|
||||
term.tabs = xrealloc(term.tabs, col * sizeof(*term.tabs));
|
||||
|
||||
- /* resize each row to new width, zero-pad if needed */
|
||||
- for (i = 0; i < minrow; i++) {
|
||||
- term.line[i] = xrealloc(term.line[i], col * sizeof(Glyph));
|
||||
- term.alt[i] = xrealloc(term.alt[i], col * sizeof(Glyph));
|
||||
- }
|
||||
-
|
||||
- /* allocate any new rows */
|
||||
- for (/* i = minrow */; i < row; i++) {
|
||||
- term.line[i] = xmalloc(col * sizeof(Glyph));
|
||||
- term.alt[i] = xmalloc(col * sizeof(Glyph));
|
||||
- }
|
||||
+ /* fix tabstops */
|
||||
if (col > term.col) {
|
||||
bp = term.tabs + term.col;
|
||||
|
||||
@@ -2599,26 +2726,16 @@ tresize(int col, int row)
|
||||
for (bp += tabspaces; bp < term.tabs + col; bp += tabspaces)
|
||||
*bp = 1;
|
||||
}
|
||||
+
|
||||
/* update terminal size */
|
||||
term.col = col;
|
||||
term.row = row;
|
||||
+ term.linelen = linelen;
|
||||
/* reset scrolling region */
|
||||
tsetscroll(0, row-1);
|
||||
/* make use of the LIMIT in tmoveto */
|
||||
tmoveto(term.c.x, term.c.y);
|
||||
- /* Clearing both screens (it makes dirty all lines) */
|
||||
- c = term.c;
|
||||
- for (i = 0; i < 2; i++) {
|
||||
- if (mincol < col && 0 < minrow) {
|
||||
- tclearregion(mincol, 0, col - 1, minrow - 1);
|
||||
- }
|
||||
- if (0 < col && minrow < row) {
|
||||
- tclearregion(0, minrow, col - 1, row - 1);
|
||||
- }
|
||||
- tswapscreen();
|
||||
- tcursor(CURSOR_LOAD);
|
||||
- }
|
||||
- term.c = c;
|
||||
+ tfulldirt();
|
||||
}
|
||||
|
||||
void
|
||||
@@ -2630,14 +2747,15 @@ resettitle(void)
|
||||
void
|
||||
drawregion(int x1, int y1, int x2, int y2)
|
||||
{
|
||||
- int y;
|
||||
+ int y, L;
|
||||
|
||||
+ L = TLINEOFFSET(y1);
|
||||
for (y = y1; y < y2; y++) {
|
||||
- if (!term.dirty[y])
|
||||
- continue;
|
||||
-
|
||||
- term.dirty[y] = 0;
|
||||
- xdrawline(term.line[y], x1, y, x2);
|
||||
+ if (term.dirty[y]) {
|
||||
+ term.dirty[y] = 0;
|
||||
+ xdrawline(TSCREEN.buffer[L], x1, y, x2);
|
||||
+ }
|
||||
+ L = (L + 1) % TSCREEN.size;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2652,14 +2770,15 @@ draw(void)
|
||||
/* adjust cursor position */
|
||||
LIMIT(term.ocx, 0, term.col-1);
|
||||
LIMIT(term.ocy, 0, term.row-1);
|
||||
- if (term.line[term.ocy][term.ocx].mode & ATTR_WDUMMY)
|
||||
+ if (TLINE(term.ocy)[term.ocx].mode & ATTR_WDUMMY)
|
||||
term.ocx--;
|
||||
- if (term.line[term.c.y][cx].mode & ATTR_WDUMMY)
|
||||
+ if (TLINE(term.c.y)[cx].mode & ATTR_WDUMMY)
|
||||
cx--;
|
||||
|
||||
drawregion(0, 0, term.col, term.row);
|
||||
- xdrawcursor(cx, term.c.y, term.line[term.c.y][cx],
|
||||
- term.ocx, term.ocy, term.line[term.ocy][term.ocx]);
|
||||
+ if (TSCREEN.off == 0)
|
||||
+ xdrawcursor(cx, term.c.y, TLINE(term.c.y)[cx],
|
||||
+ term.ocx, term.ocy, TLINE(term.ocy)[term.ocx]);
|
||||
term.ocx = cx;
|
||||
term.ocy = term.c.y;
|
||||
xfinishdraw();
|
||||
diff --git a/st.h b/st.h
|
||||
index fd3b0d8..3cea73b 100644
|
||||
--- a/st.h
|
||||
+++ b/st.h
|
||||
@@ -19,6 +19,7 @@
|
||||
|
||||
#define TRUECOLOR(r,g,b) (1 << 24 | (r) << 16 | (g) << 8 | (b))
|
||||
#define IS_TRUECOL(x) (1 << 24 & (x))
|
||||
+#define HISTSIZE 2000
|
||||
|
||||
enum glyph_attribute {
|
||||
ATTR_NULL = 0,
|
||||
diff --git a/x.c b/x.c
|
||||
index bd23686..25785a6 100644
|
||||
--- a/x.c
|
||||
+++ b/x.c
|
||||
@@ -59,6 +59,8 @@ static void zoom(const Arg *);
|
||||
static void zoomabs(const Arg *);
|
||||
static void zoomreset(const Arg *);
|
||||
static void ttysend(const Arg *);
|
||||
+void kscrollup(const Arg *);
|
||||
+void kscrolldown(const Arg *);
|
||||
|
||||
/* config.h for applying patches and the configuration. */
|
||||
#include "config.h"
|
||||
184
patches/st-xresources-20230320-45a15676.diff
Normal file
184
patches/st-xresources-20230320-45a15676.diff
Normal file
@@ -0,0 +1,184 @@
|
||||
From 6315407196933ec86be2b3c74f89bee746353e32 Mon Sep 17 00:00:00 2001
|
||||
From: harishnkr <hari2menon1234@gmail.com>
|
||||
Date: Mon, 20 Mar 2023 14:27:07 +0530
|
||||
Subject: [PATCH] Fix xresources bgcolour fgcolour and cscolour definitions
|
||||
|
||||
---
|
||||
config.def.h | 36 ++++++++++++++++++++++++
|
||||
x.c | 78 +++++++++++++++++++++++++++++++++++++++++++++++++---
|
||||
2 files changed, 110 insertions(+), 4 deletions(-)
|
||||
|
||||
diff --git a/config.def.h b/config.def.h
|
||||
index 91ab8ca..f11db58 100644
|
||||
--- a/config.def.h
|
||||
+++ b/config.def.h
|
||||
@@ -170,6 +170,42 @@ static unsigned int defaultattr = 11;
|
||||
*/
|
||||
static uint forcemousemod = ShiftMask;
|
||||
|
||||
+/*
|
||||
+ * Xresources preferences to load at startup
|
||||
+ */
|
||||
+ResourcePref resources[] = {
|
||||
+ { "font", STRING, &font },
|
||||
+ { "color0", STRING, &colorname[0] },
|
||||
+ { "color1", STRING, &colorname[1] },
|
||||
+ { "color2", STRING, &colorname[2] },
|
||||
+ { "color3", STRING, &colorname[3] },
|
||||
+ { "color4", STRING, &colorname[4] },
|
||||
+ { "color5", STRING, &colorname[5] },
|
||||
+ { "color6", STRING, &colorname[6] },
|
||||
+ { "color7", STRING, &colorname[7] },
|
||||
+ { "color8", STRING, &colorname[8] },
|
||||
+ { "color9", STRING, &colorname[9] },
|
||||
+ { "color10", STRING, &colorname[10] },
|
||||
+ { "color11", STRING, &colorname[11] },
|
||||
+ { "color12", STRING, &colorname[12] },
|
||||
+ { "color13", STRING, &colorname[13] },
|
||||
+ { "color14", STRING, &colorname[14] },
|
||||
+ { "color15", STRING, &colorname[15] },
|
||||
+ { "background", STRING, &colorname[259] },
|
||||
+ { "foreground", STRING, &colorname[258] },
|
||||
+ { "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 },
|
||||
+ { "borderpx", INTEGER, &borderpx },
|
||||
+ { "cwscale", FLOAT, &cwscale },
|
||||
+ { "chscale", FLOAT, &chscale },
|
||||
+};
|
||||
+
|
||||
/*
|
||||
* Internal mouse shortcuts.
|
||||
* Beware that overloading Button1 will disable the selection.
|
||||
diff --git a/x.c b/x.c
|
||||
index aa09997..ab10269 100644
|
||||
--- a/x.c
|
||||
+++ b/x.c
|
||||
@@ -14,6 +14,7 @@
|
||||
#include <X11/keysym.h>
|
||||
#include <X11/Xft/Xft.h>
|
||||
#include <X11/XKBlib.h>
|
||||
+#include <X11/Xresource.h>
|
||||
|
||||
char *argv0;
|
||||
#include "arg.h"
|
||||
@@ -45,6 +46,19 @@ typedef struct {
|
||||
signed char appcursor; /* application cursor */
|
||||
} Key;
|
||||
|
||||
+/* Xresources preferences */
|
||||
+enum resource_type {
|
||||
+ STRING = 0,
|
||||
+ INTEGER = 1,
|
||||
+ FLOAT = 2
|
||||
+};
|
||||
+
|
||||
+typedef struct {
|
||||
+ char *name;
|
||||
+ enum resource_type type;
|
||||
+ void *dst;
|
||||
+} ResourcePref;
|
||||
+
|
||||
/* X modifiers */
|
||||
#define XK_ANY_MOD UINT_MAX
|
||||
#define XK_NO_MOD 0
|
||||
@@ -859,8 +873,8 @@ xclear(int x1, int y1, int x2, int y2)
|
||||
void
|
||||
xhints(void)
|
||||
{
|
||||
- XClassHint class = {opt_name ? opt_name : termname,
|
||||
- opt_class ? opt_class : termname};
|
||||
+ XClassHint class = {opt_name ? opt_name : "st",
|
||||
+ opt_class ? opt_class : "St"};
|
||||
XWMHints wm = {.flags = InputHint, .input = 1};
|
||||
XSizeHints *sizeh;
|
||||
|
||||
@@ -1135,8 +1149,6 @@ xinit(int cols, int rows)
|
||||
pid_t thispid = getpid();
|
||||
XColor xmousefg, xmousebg;
|
||||
|
||||
- if (!(xw.dpy = XOpenDisplay(NULL)))
|
||||
- die("can't open display\n");
|
||||
xw.scr = XDefaultScreen(xw.dpy);
|
||||
xw.vis = XDefaultVisual(xw.dpy, xw.scr);
|
||||
|
||||
@@ -2014,6 +2026,59 @@ run(void)
|
||||
}
|
||||
}
|
||||
|
||||
+int
|
||||
+resource_load(XrmDatabase db, char *name, enum resource_type rtype, void *dst)
|
||||
+{
|
||||
+ char **sdst = dst;
|
||||
+ int *idst = dst;
|
||||
+ float *fdst = dst;
|
||||
+
|
||||
+ char fullname[256];
|
||||
+ char fullclass[256];
|
||||
+ char *type;
|
||||
+ XrmValue ret;
|
||||
+
|
||||
+ snprintf(fullname, sizeof(fullname), "%s.%s",
|
||||
+ opt_name ? opt_name : "st", name);
|
||||
+ snprintf(fullclass, sizeof(fullclass), "%s.%s",
|
||||
+ opt_class ? opt_class : "St", name);
|
||||
+ fullname[sizeof(fullname) - 1] = fullclass[sizeof(fullclass) - 1] = '\0';
|
||||
+
|
||||
+ XrmGetResource(db, fullname, fullclass, &type, &ret);
|
||||
+ if (ret.addr == NULL || strncmp("String", type, 64))
|
||||
+ return 1;
|
||||
+
|
||||
+ switch (rtype) {
|
||||
+ case STRING:
|
||||
+ *sdst = ret.addr;
|
||||
+ break;
|
||||
+ case INTEGER:
|
||||
+ *idst = strtoul(ret.addr, NULL, 10);
|
||||
+ break;
|
||||
+ case FLOAT:
|
||||
+ *fdst = strtof(ret.addr, NULL);
|
||||
+ break;
|
||||
+ }
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+void
|
||||
+config_init(void)
|
||||
+{
|
||||
+ char *resm;
|
||||
+ XrmDatabase db;
|
||||
+ ResourcePref *p;
|
||||
+
|
||||
+ XrmInitialize();
|
||||
+ resm = XResourceManagerString(xw.dpy);
|
||||
+ if (!resm)
|
||||
+ return;
|
||||
+
|
||||
+ db = XrmGetStringDatabase(resm);
|
||||
+ for (p = resources; p < resources + LEN(resources); p++)
|
||||
+ resource_load(db, p->name, p->type, p->dst);
|
||||
+}
|
||||
+
|
||||
void
|
||||
usage(void)
|
||||
{
|
||||
@@ -2087,6 +2152,11 @@ run:
|
||||
|
||||
setlocale(LC_CTYPE, "");
|
||||
XSetLocaleModifiers("");
|
||||
+
|
||||
+ if(!(xw.dpy = XOpenDisplay(NULL)))
|
||||
+ die("Can't open display\n");
|
||||
+
|
||||
+ config_init();
|
||||
cols = MAX(cols, 1);
|
||||
rows = MAX(rows, 1);
|
||||
tnew(cols, rows);
|
||||
--
|
||||
2.39.2
|
||||
|
||||
444
st.c
444
st.c
@@ -43,6 +43,10 @@
|
||||
#define ISCONTROL(c) (ISCONTROLC0(c) || ISCONTROLC1(c))
|
||||
#define ISDELIM(u) (u && wcschr(worddelimiters, u))
|
||||
|
||||
#define TSCREEN term.screen[IS_SET(MODE_ALTSCREEN)]
|
||||
#define TLINEOFFSET(y) (((y) + TSCREEN.cur - TSCREEN.off + TSCREEN.size) % TSCREEN.size)
|
||||
#define TLINE(y) (TSCREEN.buffer[TLINEOFFSET(y)])
|
||||
|
||||
enum term_mode {
|
||||
MODE_WRAP = 1 << 0,
|
||||
MODE_INSERT = 1 << 1,
|
||||
@@ -109,12 +113,21 @@ typedef struct {
|
||||
int alt;
|
||||
} Selection;
|
||||
|
||||
/* Screen lines */
|
||||
typedef struct {
|
||||
Line* buffer; /* ring buffer */
|
||||
int size; /* size of buffer */
|
||||
int cur; /* start of active screen */
|
||||
int off; /* scrollback line offset */
|
||||
TCursor sc; /* saved cursor */
|
||||
} LineBuffer;
|
||||
|
||||
/* Internal representation of the screen */
|
||||
typedef struct {
|
||||
int row; /* nb row */
|
||||
int col; /* nb col */
|
||||
Line *line; /* screen */
|
||||
Line *alt; /* alternate screen */
|
||||
LineBuffer screen[2]; /* screen and alternate screen */
|
||||
int linelen; /* allocated line length */
|
||||
int *dirty; /* dirtyness of lines */
|
||||
TCursor c; /* cursor */
|
||||
int ocx; /* old cursor col */
|
||||
@@ -203,6 +216,8 @@ static void tdeftran(char);
|
||||
static void tstrsequence(uchar);
|
||||
|
||||
static void drawregion(int, int, int, int);
|
||||
static void clearline(Line, Glyph, int, int);
|
||||
static Line ensureline(Line);
|
||||
|
||||
static void selnormalize(void);
|
||||
static void selscroll(int, int);
|
||||
@@ -408,11 +423,12 @@ int
|
||||
tlinelen(int y)
|
||||
{
|
||||
int i = term.col;
|
||||
Line line = TLINE(y);
|
||||
|
||||
if (term.line[y][i - 1].mode & ATTR_WRAP)
|
||||
if (line[i - 1].mode & ATTR_WRAP)
|
||||
return i;
|
||||
|
||||
while (i > 0 && term.line[y][i - 1].u == ' ')
|
||||
while (i > 0 && line[i - 1].u == ' ')
|
||||
--i;
|
||||
|
||||
return i;
|
||||
@@ -521,7 +537,7 @@ selsnap(int *x, int *y, int direction)
|
||||
* Snap around if the word wraps around at the end or
|
||||
* beginning of a line.
|
||||
*/
|
||||
prevgp = &term.line[*y][*x];
|
||||
prevgp = &TLINE(*y)[*x];
|
||||
prevdelim = ISDELIM(prevgp->u);
|
||||
for (;;) {
|
||||
newx = *x + direction;
|
||||
@@ -536,14 +552,14 @@ selsnap(int *x, int *y, int direction)
|
||||
yt = *y, xt = *x;
|
||||
else
|
||||
yt = newy, xt = newx;
|
||||
if (!(term.line[yt][xt].mode & ATTR_WRAP))
|
||||
if (!(TLINE(yt)[xt].mode & ATTR_WRAP))
|
||||
break;
|
||||
}
|
||||
|
||||
if (newx >= tlinelen(newy))
|
||||
break;
|
||||
|
||||
gp = &term.line[newy][newx];
|
||||
gp = &TLINE(newy)[newx];
|
||||
delim = ISDELIM(gp->u);
|
||||
if (!(gp->mode & ATTR_WDUMMY) && (delim != prevdelim
|
||||
|| (delim && gp->u != prevgp->u)))
|
||||
@@ -564,14 +580,14 @@ selsnap(int *x, int *y, int direction)
|
||||
*x = (direction < 0) ? 0 : term.col - 1;
|
||||
if (direction < 0) {
|
||||
for (; *y > 0; *y += direction) {
|
||||
if (!(term.line[*y-1][term.col-1].mode
|
||||
if (!(TLINE(*y-1)[term.col-1].mode
|
||||
& ATTR_WRAP)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (direction > 0) {
|
||||
for (; *y < term.row-1; *y += direction) {
|
||||
if (!(term.line[*y][term.col-1].mode
|
||||
if (!(TLINE(*y)[term.col-1].mode
|
||||
& ATTR_WRAP)) {
|
||||
break;
|
||||
}
|
||||
@@ -602,13 +618,13 @@ getsel(void)
|
||||
}
|
||||
|
||||
if (sel.type == SEL_RECTANGULAR) {
|
||||
gp = &term.line[y][sel.nb.x];
|
||||
gp = &TLINE(y)[sel.nb.x];
|
||||
lastx = sel.ne.x;
|
||||
} else {
|
||||
gp = &term.line[y][sel.nb.y == y ? sel.nb.x : 0];
|
||||
gp = &TLINE(y)[sel.nb.y == y ? sel.nb.x : 0];
|
||||
lastx = (sel.ne.y == y) ? sel.ne.x : term.col-1;
|
||||
}
|
||||
last = &term.line[y][MIN(lastx, linelen-1)];
|
||||
last = &TLINE(y)[MIN(lastx, linelen-1)];
|
||||
while (last >= gp && last->u == ' ')
|
||||
--last;
|
||||
|
||||
@@ -939,7 +955,7 @@ ttyresize(int tw, int th)
|
||||
}
|
||||
|
||||
void
|
||||
ttyhangup()
|
||||
ttyhangup(void)
|
||||
{
|
||||
/* Send SIGHUP to shell */
|
||||
kill(pid, SIGHUP);
|
||||
@@ -949,12 +965,15 @@ int
|
||||
tattrset(int attr)
|
||||
{
|
||||
int i, j;
|
||||
int y = TLINEOFFSET(0);
|
||||
|
||||
for (i = 0; i < term.row-1; i++) {
|
||||
Line line = TSCREEN.buffer[y];
|
||||
for (j = 0; j < term.col-1; j++) {
|
||||
if (term.line[i][j].mode & attr)
|
||||
if (line[j].mode & attr)
|
||||
return 1;
|
||||
}
|
||||
y = (y+1) % TSCREEN.size;
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -976,14 +995,17 @@ void
|
||||
tsetdirtattr(int attr)
|
||||
{
|
||||
int i, j;
|
||||
int y = TLINEOFFSET(0);
|
||||
|
||||
for (i = 0; i < term.row-1; i++) {
|
||||
Line line = TSCREEN.buffer[y];
|
||||
for (j = 0; j < term.col-1; j++) {
|
||||
if (term.line[i][j].mode & attr) {
|
||||
if (line[j].mode & attr) {
|
||||
tsetdirt(i, i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
y = (y+1) % TSCREEN.size;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -996,27 +1018,19 @@ tfulldirt(void)
|
||||
void
|
||||
tcursor(int mode)
|
||||
{
|
||||
static TCursor c[2];
|
||||
int alt = IS_SET(MODE_ALTSCREEN);
|
||||
|
||||
if (mode == CURSOR_SAVE) {
|
||||
c[alt] = term.c;
|
||||
TSCREEN.sc = term.c;
|
||||
} else if (mode == CURSOR_LOAD) {
|
||||
term.c = c[alt];
|
||||
tmoveto(c[alt].x, c[alt].y);
|
||||
term.c = TSCREEN.sc;
|
||||
tmoveto(term.c.x, term.c.y);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
treset(void)
|
||||
{
|
||||
uint i;
|
||||
|
||||
term.c = (TCursor){{
|
||||
.mode = ATTR_NULL,
|
||||
.fg = defaultfg,
|
||||
.bg = defaultbg
|
||||
}, .x = 0, .y = 0, .state = CURSOR_DEFAULT};
|
||||
int i, j;
|
||||
Glyph g = (Glyph){ .fg = defaultfg, .bg = defaultbg};
|
||||
|
||||
memset(term.tabs, 0, term.col * sizeof(*term.tabs));
|
||||
for (i = tabspaces; i < term.col; i += tabspaces)
|
||||
@@ -1028,17 +1042,37 @@ treset(void)
|
||||
term.charset = 0;
|
||||
|
||||
for (i = 0; i < 2; i++) {
|
||||
tmoveto(0, 0);
|
||||
tcursor(CURSOR_SAVE);
|
||||
tclearregion(0, 0, term.col-1, term.row-1);
|
||||
tswapscreen();
|
||||
term.screen[i].sc = (TCursor){{
|
||||
.fg = defaultfg,
|
||||
.bg = defaultbg
|
||||
}};
|
||||
term.screen[i].cur = 0;
|
||||
term.screen[i].off = 0;
|
||||
for (j = 0; j < term.row; ++j) {
|
||||
if (term.col != term.linelen)
|
||||
term.screen[i].buffer[j] = xrealloc(term.screen[i].buffer[j], term.col * sizeof(Glyph));
|
||||
clearline(term.screen[i].buffer[j], g, 0, term.col);
|
||||
}
|
||||
for (j = term.row; j < term.screen[i].size; ++j) {
|
||||
free(term.screen[i].buffer[j]);
|
||||
term.screen[i].buffer[j] = NULL;
|
||||
}
|
||||
}
|
||||
tcursor(CURSOR_LOAD);
|
||||
term.linelen = term.col;
|
||||
tfulldirt();
|
||||
}
|
||||
|
||||
void
|
||||
tnew(int col, int row)
|
||||
{
|
||||
term = (Term){ .c = { .attr = { .fg = defaultfg, .bg = defaultbg } } };
|
||||
int i;
|
||||
term = (Term){};
|
||||
term.screen[0].buffer = xmalloc(HISTSIZE * sizeof(Line));
|
||||
term.screen[0].size = HISTSIZE;
|
||||
term.screen[1].buffer = NULL;
|
||||
for (i = 0; i < HISTSIZE; ++i) term.screen[0].buffer[i] = NULL;
|
||||
|
||||
tresize(col, row);
|
||||
treset();
|
||||
}
|
||||
@@ -1046,14 +1080,42 @@ tnew(int col, int row)
|
||||
void
|
||||
tswapscreen(void)
|
||||
{
|
||||
Line *tmp = term.line;
|
||||
|
||||
term.line = term.alt;
|
||||
term.alt = tmp;
|
||||
term.mode ^= MODE_ALTSCREEN;
|
||||
tfulldirt();
|
||||
}
|
||||
|
||||
void
|
||||
kscrollup(const Arg *a)
|
||||
{
|
||||
float n = a->f;
|
||||
|
||||
if (IS_SET(MODE_ALTSCREEN))
|
||||
return;
|
||||
|
||||
if (n < 0) n = MAX((-n) * term.row, 1);
|
||||
if (n > TSCREEN.size - term.row - TSCREEN.off) n = TSCREEN.size - term.row - TSCREEN.off;
|
||||
while (!TLINE((int)-n)) --n;
|
||||
TSCREEN.off += n;
|
||||
selscroll(0, n);
|
||||
tfulldirt();
|
||||
}
|
||||
|
||||
void
|
||||
kscrolldown(const Arg *a)
|
||||
{
|
||||
|
||||
float n = a->f;
|
||||
|
||||
if (IS_SET(MODE_ALTSCREEN))
|
||||
return;
|
||||
|
||||
if (n < 0) n = MAX((-n) * term.row, 1);
|
||||
if (n > TSCREEN.off) n = TSCREEN.off;
|
||||
TSCREEN.off -= n;
|
||||
selscroll(0, -n);
|
||||
tfulldirt();
|
||||
}
|
||||
|
||||
void
|
||||
tscrolldown(int orig, int n)
|
||||
{
|
||||
@@ -1062,15 +1124,29 @@ tscrolldown(int orig, int n)
|
||||
|
||||
LIMIT(n, 0, term.bot-orig+1);
|
||||
|
||||
tsetdirt(orig, term.bot-n);
|
||||
tclearregion(0, term.bot-n+1, term.col-1, term.bot);
|
||||
|
||||
for (i = term.bot; i >= orig+n; i--) {
|
||||
temp = term.line[i];
|
||||
term.line[i] = term.line[i-n];
|
||||
term.line[i-n] = temp;
|
||||
/* Ensure that lines are allocated */
|
||||
for (i = -n; i < 0; i++) {
|
||||
TLINE(i) = ensureline(TLINE(i));
|
||||
}
|
||||
|
||||
/* Shift non-scrolling areas in ring buffer */
|
||||
for (i = term.bot+1; i < term.row; i++) {
|
||||
temp = TLINE(i);
|
||||
TLINE(i) = TLINE(i-n);
|
||||
TLINE(i-n) = temp;
|
||||
}
|
||||
for (i = 0; i < orig; i++) {
|
||||
temp = TLINE(i);
|
||||
TLINE(i) = TLINE(i-n);
|
||||
TLINE(i-n) = temp;
|
||||
}
|
||||
|
||||
/* Scroll buffer */
|
||||
TSCREEN.cur = (TSCREEN.cur + TSCREEN.size - n) % TSCREEN.size;
|
||||
/* Clear lines that have entered the view */
|
||||
tclearregion(0, orig, term.linelen-1, orig+n-1);
|
||||
/* Redraw portion of the screen that has scrolled */
|
||||
tsetdirt(orig+n-1, term.bot);
|
||||
selscroll(orig, n);
|
||||
}
|
||||
|
||||
@@ -1082,22 +1158,36 @@ tscrollup(int orig, int n)
|
||||
|
||||
LIMIT(n, 0, term.bot-orig+1);
|
||||
|
||||
tclearregion(0, orig, term.col-1, orig+n-1);
|
||||
tsetdirt(orig+n, term.bot);
|
||||
|
||||
for (i = orig; i <= term.bot-n; i++) {
|
||||
temp = term.line[i];
|
||||
term.line[i] = term.line[i+n];
|
||||
term.line[i+n] = temp;
|
||||
/* Ensure that lines are allocated */
|
||||
for (i = term.row; i < term.row + n; i++) {
|
||||
TLINE(i) = ensureline(TLINE(i));
|
||||
}
|
||||
|
||||
/* Shift non-scrolling areas in ring buffer */
|
||||
for (i = orig-1; i >= 0; i--) {
|
||||
temp = TLINE(i);
|
||||
TLINE(i) = TLINE(i+n);
|
||||
TLINE(i+n) = temp;
|
||||
}
|
||||
for (i = term.row-1; i >term.bot; i--) {
|
||||
temp = TLINE(i);
|
||||
TLINE(i) = TLINE(i+n);
|
||||
TLINE(i+n) = temp;
|
||||
}
|
||||
|
||||
/* Scroll buffer */
|
||||
TSCREEN.cur = (TSCREEN.cur + n) % TSCREEN.size;
|
||||
/* Clear lines that have entered the view */
|
||||
tclearregion(0, term.bot-n+1, term.linelen-1, term.bot);
|
||||
/* Redraw portion of the screen that has scrolled */
|
||||
tsetdirt(orig, term.bot-n+1);
|
||||
selscroll(orig, -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)) {
|
||||
@@ -1132,6 +1222,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 == '?') {
|
||||
@@ -1149,7 +1240,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++;
|
||||
}
|
||||
@@ -1194,6 +1287,7 @@ tsetchar(Rune u, const Glyph *attr, int x, int y)
|
||||
"⎻", "─", "⎼", "⎽", "├", "┤", "┴", "┬", /* p - w */
|
||||
"│", "≤", "≥", "π", "≠", "£", "·", /* x - ~ */
|
||||
};
|
||||
Line line = TLINE(y);
|
||||
|
||||
/*
|
||||
* The table is proudly stolen from rxvt.
|
||||
@@ -1202,25 +1296,25 @@ tsetchar(Rune u, const Glyph *attr, int x, int y)
|
||||
BETWEEN(u, 0x41, 0x7e) && vt100_0[u - 0x41])
|
||||
utf8decode(vt100_0[u - 0x41], &u, UTF_SIZ);
|
||||
|
||||
if (term.line[y][x].mode & ATTR_WIDE) {
|
||||
if (line[x].mode & ATTR_WIDE) {
|
||||
if (x+1 < term.col) {
|
||||
term.line[y][x+1].u = ' ';
|
||||
term.line[y][x+1].mode &= ~ATTR_WDUMMY;
|
||||
line[x+1].u = ' ';
|
||||
line[x+1].mode &= ~ATTR_WDUMMY;
|
||||
}
|
||||
} else if (term.line[y][x].mode & ATTR_WDUMMY) {
|
||||
term.line[y][x-1].u = ' ';
|
||||
term.line[y][x-1].mode &= ~ATTR_WIDE;
|
||||
} else if (line[x].mode & ATTR_WDUMMY) {
|
||||
line[x-1].u = ' ';
|
||||
line[x-1].mode &= ~ATTR_WIDE;
|
||||
}
|
||||
|
||||
term.dirty[y] = 1;
|
||||
term.line[y][x] = *attr;
|
||||
term.line[y][x].u = u;
|
||||
line[x] = *attr;
|
||||
line[x].u = u;
|
||||
}
|
||||
|
||||
void
|
||||
tclearregion(int x1, int y1, int x2, int y2)
|
||||
{
|
||||
int x, y, temp;
|
||||
int x, y, L, S, temp;
|
||||
Glyph *gp;
|
||||
|
||||
if (x1 > x2)
|
||||
@@ -1228,15 +1322,16 @@ tclearregion(int x1, int y1, int x2, int y2)
|
||||
if (y1 > y2)
|
||||
temp = y1, y1 = y2, y2 = temp;
|
||||
|
||||
LIMIT(x1, 0, term.col-1);
|
||||
LIMIT(x2, 0, term.col-1);
|
||||
LIMIT(x1, 0, term.linelen-1);
|
||||
LIMIT(x2, 0, term.linelen-1);
|
||||
LIMIT(y1, 0, term.row-1);
|
||||
LIMIT(y2, 0, term.row-1);
|
||||
|
||||
L = TLINEOFFSET(y1);
|
||||
for (y = y1; y <= y2; y++) {
|
||||
term.dirty[y] = 1;
|
||||
for (x = x1; x <= x2; x++) {
|
||||
gp = &term.line[y][x];
|
||||
gp = &TSCREEN.buffer[L][x];
|
||||
if (selected(x, y))
|
||||
selclear();
|
||||
gp->fg = term.c.attr.fg;
|
||||
@@ -1244,6 +1339,7 @@ tclearregion(int x1, int y1, int x2, int y2)
|
||||
gp->mode = 0;
|
||||
gp->u = ' ';
|
||||
}
|
||||
L = (L + 1) % TSCREEN.size;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1258,7 +1354,7 @@ tdeletechar(int n)
|
||||
dst = term.c.x;
|
||||
src = term.c.x + n;
|
||||
size = term.col - src;
|
||||
line = term.line[term.c.y];
|
||||
line = TLINE(term.c.y);
|
||||
|
||||
memmove(&line[dst], &line[src], size * sizeof(Glyph));
|
||||
tclearregion(term.col-n, term.c.y, term.col-1, term.c.y);
|
||||
@@ -1275,7 +1371,7 @@ tinsertblank(int n)
|
||||
dst = term.c.x + n;
|
||||
src = term.c.x;
|
||||
size = term.col - dst;
|
||||
line = term.line[term.c.y];
|
||||
line = TLINE(term.c.y);
|
||||
|
||||
memmove(&line[dst], &line[src], size * sizeof(Glyph));
|
||||
tclearregion(src, term.c.y, dst - 1, term.c.y);
|
||||
@@ -1417,16 +1513,22 @@ tsetattr(const int *attr, int l)
|
||||
if ((idx = tdefcolor(attr, &i, l)) >= 0)
|
||||
term.c.attr.fg = idx;
|
||||
break;
|
||||
case 39:
|
||||
case 39: /* set foreground color to default */
|
||||
term.c.attr.fg = defaultfg;
|
||||
break;
|
||||
case 48:
|
||||
if ((idx = tdefcolor(attr, &i, l)) >= 0)
|
||||
term.c.attr.bg = idx;
|
||||
break;
|
||||
case 49:
|
||||
case 49: /* set background color to default */
|
||||
term.c.attr.bg = defaultbg;
|
||||
break;
|
||||
case 58:
|
||||
/* This starts a sequence to change the color of
|
||||
* "underline" pixels. We don't support that and
|
||||
* instead eat up a following "5;n" or "2;r;g;b". */
|
||||
tdefcolor(attr, &i, l);
|
||||
break;
|
||||
default:
|
||||
if (BETWEEN(attr[i], 30, 37)) {
|
||||
term.c.attr.fg = attr[i] - 30;
|
||||
@@ -1523,7 +1625,7 @@ tsetmode(int priv, int set, const int *args, int narg)
|
||||
case 1006: /* 1006: extended reporting mode */
|
||||
xsetmode(set, MODE_MOUSESGR);
|
||||
break;
|
||||
case 1034:
|
||||
case 1034: /* 1034: enable 8-bit mode for keyboard input */
|
||||
xsetmode(set, MODE_8BIT);
|
||||
break;
|
||||
case 1049: /* swap screen & set/restore cursor as xterm */
|
||||
@@ -1531,8 +1633,8 @@ tsetmode(int priv, int set, const int *args, int narg)
|
||||
break;
|
||||
tcursor((set) ? CURSOR_SAVE : CURSOR_LOAD);
|
||||
/* FALLTHROUGH */
|
||||
case 47: /* swap screen */
|
||||
case 1047:
|
||||
case 47: /* swap screen buffer */
|
||||
case 1047: /* swap screen buffer */
|
||||
if (!allowaltscreen)
|
||||
break;
|
||||
alt = IS_SET(MODE_ALTSCREEN);
|
||||
@@ -1545,7 +1647,7 @@ tsetmode(int priv, int set, const int *args, int narg)
|
||||
if (*args != 1049)
|
||||
break;
|
||||
/* FALLTHROUGH */
|
||||
case 1048:
|
||||
case 1048: /* save/restore cursor (like DECSC/DECRC) */
|
||||
tcursor((set) ? CURSOR_SAVE : CURSOR_LOAD);
|
||||
break;
|
||||
case 2004: /* 2004: bracketed paste mode */
|
||||
@@ -1643,7 +1745,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);
|
||||
@@ -1702,7 +1804,7 @@ csihandle(void)
|
||||
}
|
||||
break;
|
||||
case 1: /* above */
|
||||
if (term.c.y > 1)
|
||||
if (term.c.y > 0)
|
||||
tclearregion(0, 0, term.col-1, term.c.y-1);
|
||||
tclearregion(0, term.c.y, term.c.x, term.c.y);
|
||||
break;
|
||||
@@ -1728,6 +1830,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;
|
||||
@@ -1769,11 +1872,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);
|
||||
ttywrite(buf, len, 0);
|
||||
break;
|
||||
default:
|
||||
goto unknown;
|
||||
}
|
||||
break;
|
||||
case 'r': /* DECSTBM -- Set Scrolling Region */
|
||||
@@ -1790,7 +1900,11 @@ csihandle(void)
|
||||
tcursor(CURSOR_SAVE);
|
||||
break;
|
||||
case 'u': /* DECRC -- Restore cursor position (ANSI.SYS) */
|
||||
if (csiescseq.priv) {
|
||||
goto unknown;
|
||||
} else {
|
||||
tcursor(CURSOR_LOAD);
|
||||
}
|
||||
break;
|
||||
case ' ':
|
||||
switch (csiescseq.mode[1]) {
|
||||
@@ -1892,7 +2006,7 @@ strhandle(void)
|
||||
if (narg > 1)
|
||||
xsettitle(strescseq.args[1]);
|
||||
return;
|
||||
case 52:
|
||||
case 52: /* manipulate selection data */
|
||||
if (narg > 2 && allowwindowops) {
|
||||
dec = base64dec(strescseq.args[2]);
|
||||
if (dec) {
|
||||
@@ -1903,9 +2017,9 @@ strhandle(void)
|
||||
}
|
||||
}
|
||||
return;
|
||||
case 10:
|
||||
case 11:
|
||||
case 12:
|
||||
case 10: /* set dynamic VT100 text foreground color */
|
||||
case 11: /* set dynamic VT100 text background color */
|
||||
case 12: /* set dynamic text cursor color */
|
||||
if (narg < 2)
|
||||
break;
|
||||
p = strescseq.args[1];
|
||||
@@ -1932,8 +2046,10 @@ strhandle(void)
|
||||
if (p && !strcmp(p, "?")) {
|
||||
osc_color_response(j, 0, 1);
|
||||
} else if (xsetcolorname(j, p)) {
|
||||
if (par == 104 && narg <= 1)
|
||||
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 {
|
||||
@@ -1944,6 +2060,19 @@ strhandle(void)
|
||||
tfulldirt();
|
||||
}
|
||||
return;
|
||||
case 110: /* reset dynamic VT100 text foreground color */
|
||||
case 111: /* reset dynamic VT100 text background color */
|
||||
case 112: /* reset dynamic text cursor color */
|
||||
if (narg != 1)
|
||||
break;
|
||||
if ((j = par - 110) < 0 || j >= LEN(osc_table))
|
||||
break; /* shouldn't be possible */
|
||||
if (xsetcolorname(osc_table[j].idx, NULL)) {
|
||||
fprintf(stderr, "erresc: %s color not found\n", osc_table[j].str);
|
||||
} else {
|
||||
tfulldirt();
|
||||
}
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case 'k': /* old title set compatibility */
|
||||
@@ -2069,7 +2198,7 @@ tdumpline(int n)
|
||||
char buf[UTF_SIZ];
|
||||
const Glyph *bp, *end;
|
||||
|
||||
bp = &term.line[n][0];
|
||||
bp = &TLINE(n)[0];
|
||||
end = &bp[MIN(tlinelen(n), term.col) - 1];
|
||||
if (bp != end || bp->u != ' ') {
|
||||
for ( ; bp <= end; ++bp)
|
||||
@@ -2321,6 +2450,7 @@ eschandle(uchar ascii)
|
||||
treset();
|
||||
resettitle();
|
||||
xloadcols();
|
||||
xsetmode(0, MODE_HIDE);
|
||||
break;
|
||||
case '=': /* DECPAM -- Application keypad */
|
||||
xsetmode(1, MODE_APPKEYPAD);
|
||||
@@ -2413,6 +2543,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
|
||||
@@ -2452,19 +2585,24 @@ check_control_code:
|
||||
if (selected(term.c.x, term.c.y))
|
||||
selclear();
|
||||
|
||||
gp = &term.line[term.c.y][term.c.x];
|
||||
gp = &TLINE(term.c.y)[term.c.x];
|
||||
if (IS_SET(MODE_WRAP) && (term.c.state & CURSOR_WRAPNEXT)) {
|
||||
gp->mode |= ATTR_WRAP;
|
||||
tnewline(1);
|
||||
gp = &term.line[term.c.y][term.c.x];
|
||||
gp = &TLINE(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) {
|
||||
if (IS_SET(MODE_WRAP))
|
||||
tnewline(1);
|
||||
gp = &term.line[term.c.y][term.c.x];
|
||||
else
|
||||
tmoveto(term.col - width, term.c.y);
|
||||
gp = &TLINE(term.c.y)[term.c.x];
|
||||
}
|
||||
|
||||
tsetchar(u, &term.c.attr, term.c.x, term.c.y);
|
||||
@@ -2495,6 +2633,11 @@ twrite(const char *buf, int buflen, int show_ctrl)
|
||||
Rune u;
|
||||
int n;
|
||||
|
||||
if (TSCREEN.off) {
|
||||
TSCREEN.off = 0;
|
||||
tfulldirt();
|
||||
}
|
||||
|
||||
for (n = 0; n < buflen; n += charsize) {
|
||||
if (IS_SET(MODE_UTF8)) {
|
||||
/* process a complete utf8 char */
|
||||
@@ -2521,56 +2664,85 @@ twrite(const char *buf, int buflen, int show_ctrl)
|
||||
}
|
||||
|
||||
void
|
||||
tresize(int col, int row)
|
||||
clearline(Line line, Glyph g, int x, int xend)
|
||||
{
|
||||
int i;
|
||||
g.mode = 0;
|
||||
g.u = ' ';
|
||||
for (i = x; i < xend; ++i) {
|
||||
line[i] = g;
|
||||
}
|
||||
}
|
||||
|
||||
Line
|
||||
ensureline(Line line)
|
||||
{
|
||||
if (!line) {
|
||||
line = xmalloc(term.linelen * sizeof(Glyph));
|
||||
}
|
||||
return line;
|
||||
}
|
||||
|
||||
void
|
||||
tresize(int col, int row)
|
||||
{
|
||||
int i, j;
|
||||
int minrow = MIN(row, term.row);
|
||||
int mincol = MIN(col, term.col);
|
||||
int linelen = MAX(col, term.linelen);
|
||||
int *bp;
|
||||
TCursor c;
|
||||
|
||||
if (col < 1 || row < 1) {
|
||||
if (col < 1 || row < 1 || row > HISTSIZE) {
|
||||
fprintf(stderr,
|
||||
"tresize: error resizing to %dx%d\n", col, row);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* slide screen to keep cursor where we expect it -
|
||||
* tscrollup would work here, but we can optimize to
|
||||
* memmove because we're freeing the earlier lines
|
||||
*/
|
||||
for (i = 0; i <= term.c.y - row; i++) {
|
||||
free(term.line[i]);
|
||||
free(term.alt[i]);
|
||||
/* Shift buffer to keep the cursor where we expect it */
|
||||
if (row <= term.c.y) {
|
||||
term.screen[0].cur = (term.screen[0].cur - row + term.c.y + 1) % term.screen[0].size;
|
||||
}
|
||||
/* ensure that both src and dst are not NULL */
|
||||
if (i > 0) {
|
||||
memmove(term.line, term.line + i, row * sizeof(Line));
|
||||
memmove(term.alt, term.alt + i, row * sizeof(Line));
|
||||
|
||||
/* Resize and clear line buffers as needed */
|
||||
if (linelen > term.linelen) {
|
||||
for (i = 0; i < term.screen[0].size; ++i) {
|
||||
if (term.screen[0].buffer[i]) {
|
||||
term.screen[0].buffer[i] = xrealloc(term.screen[0].buffer[i], linelen * sizeof(Glyph));
|
||||
clearline(term.screen[0].buffer[i], term.c.attr, term.linelen, linelen);
|
||||
}
|
||||
for (i += row; i < term.row; i++) {
|
||||
free(term.line[i]);
|
||||
free(term.alt[i]);
|
||||
}
|
||||
for (i = 0; i < minrow; ++i) {
|
||||
term.screen[1].buffer[i] = xrealloc(term.screen[1].buffer[i], linelen * sizeof(Glyph));
|
||||
clearline(term.screen[1].buffer[i], term.c.attr, term.linelen, linelen);
|
||||
}
|
||||
}
|
||||
/* Allocate all visible lines for regular line buffer */
|
||||
for (j = term.screen[0].cur, i = 0; i < row; ++i, j = (j + 1) % term.screen[0].size)
|
||||
{
|
||||
if (!term.screen[0].buffer[j]) {
|
||||
term.screen[0].buffer[j] = xmalloc(linelen * sizeof(Glyph));
|
||||
}
|
||||
if (i >= term.row) {
|
||||
clearline(term.screen[0].buffer[j], term.c.attr, 0, linelen);
|
||||
}
|
||||
}
|
||||
/* Resize alt screen */
|
||||
term.screen[1].cur = 0;
|
||||
term.screen[1].size = row;
|
||||
for (i = row; i < term.row; ++i) {
|
||||
free(term.screen[1].buffer[i]);
|
||||
}
|
||||
term.screen[1].buffer = xrealloc(term.screen[1].buffer, row * sizeof(Line));
|
||||
for (i = term.row; i < row; ++i) {
|
||||
term.screen[1].buffer[i] = xmalloc(linelen * sizeof(Glyph));
|
||||
clearline(term.screen[1].buffer[i], term.c.attr, 0, linelen);
|
||||
}
|
||||
|
||||
/* resize to new height */
|
||||
term.line = xrealloc(term.line, row * sizeof(Line));
|
||||
term.alt = xrealloc(term.alt, row * sizeof(Line));
|
||||
term.dirty = xrealloc(term.dirty, row * sizeof(*term.dirty));
|
||||
term.tabs = xrealloc(term.tabs, col * sizeof(*term.tabs));
|
||||
|
||||
/* resize each row to new width, zero-pad if needed */
|
||||
for (i = 0; i < minrow; i++) {
|
||||
term.line[i] = xrealloc(term.line[i], col * sizeof(Glyph));
|
||||
term.alt[i] = xrealloc(term.alt[i], col * sizeof(Glyph));
|
||||
}
|
||||
|
||||
/* allocate any new rows */
|
||||
for (/* i = minrow */; i < row; i++) {
|
||||
term.line[i] = xmalloc(col * sizeof(Glyph));
|
||||
term.alt[i] = xmalloc(col * sizeof(Glyph));
|
||||
}
|
||||
/* fix tabstops */
|
||||
if (col > term.col) {
|
||||
bp = term.tabs + term.col;
|
||||
|
||||
@@ -2580,26 +2752,16 @@ tresize(int col, int row)
|
||||
for (bp += tabspaces; bp < term.tabs + col; bp += tabspaces)
|
||||
*bp = 1;
|
||||
}
|
||||
|
||||
/* update terminal size */
|
||||
term.col = col;
|
||||
term.row = row;
|
||||
term.linelen = linelen;
|
||||
/* reset scrolling region */
|
||||
tsetscroll(0, row-1);
|
||||
/* make use of the LIMIT in tmoveto */
|
||||
tmoveto(term.c.x, term.c.y);
|
||||
/* Clearing both screens (it makes dirty all lines) */
|
||||
c = term.c;
|
||||
for (i = 0; i < 2; i++) {
|
||||
if (mincol < col && 0 < minrow) {
|
||||
tclearregion(mincol, 0, col - 1, minrow - 1);
|
||||
}
|
||||
if (0 < col && minrow < row) {
|
||||
tclearregion(0, minrow, col - 1, row - 1);
|
||||
}
|
||||
tswapscreen();
|
||||
tcursor(CURSOR_LOAD);
|
||||
}
|
||||
term.c = c;
|
||||
tfulldirt();
|
||||
}
|
||||
|
||||
void
|
||||
@@ -2611,14 +2773,15 @@ resettitle(void)
|
||||
void
|
||||
drawregion(int x1, int y1, int x2, int y2)
|
||||
{
|
||||
int y;
|
||||
int y, L;
|
||||
|
||||
L = TLINEOFFSET(y1);
|
||||
for (y = y1; y < y2; y++) {
|
||||
if (!term.dirty[y])
|
||||
continue;
|
||||
|
||||
if (term.dirty[y]) {
|
||||
term.dirty[y] = 0;
|
||||
xdrawline(term.line[y], x1, y, x2);
|
||||
xdrawline(TSCREEN.buffer[L], x1, y, x2);
|
||||
}
|
||||
L = (L + 1) % TSCREEN.size;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2633,14 +2796,15 @@ draw(void)
|
||||
/* adjust cursor position */
|
||||
LIMIT(term.ocx, 0, term.col-1);
|
||||
LIMIT(term.ocy, 0, term.row-1);
|
||||
if (term.line[term.ocy][term.ocx].mode & ATTR_WDUMMY)
|
||||
if (TLINE(term.ocy)[term.ocx].mode & ATTR_WDUMMY)
|
||||
term.ocx--;
|
||||
if (term.line[term.c.y][cx].mode & ATTR_WDUMMY)
|
||||
if (TLINE(term.c.y)[cx].mode & ATTR_WDUMMY)
|
||||
cx--;
|
||||
|
||||
drawregion(0, 0, term.col, term.row);
|
||||
xdrawcursor(cx, term.c.y, term.line[term.c.y][cx],
|
||||
term.ocx, term.ocy, term.line[term.ocy][term.ocx]);
|
||||
if (TSCREEN.off == 0)
|
||||
xdrawcursor(cx, term.c.y, TLINE(term.c.y)[cx],
|
||||
term.ocx, term.ocy, TLINE(term.ocy)[term.ocx]);
|
||||
term.ocx = cx;
|
||||
term.ocy = term.c.y;
|
||||
xfinishdraw();
|
||||
|
||||
1
st.h
1
st.h
@@ -19,6 +19,7 @@
|
||||
|
||||
#define TRUECOLOR(r,g,b) (1 << 24 | (r) << 16 | (g) << 8 | (b))
|
||||
#define IS_TRUECOL(x) (1 << 24 & (x))
|
||||
#define HISTSIZE 2000
|
||||
|
||||
enum glyph_attribute {
|
||||
ATTR_NULL = 0,
|
||||
|
||||
4
st.info
4
st.info
@@ -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)
|
||||
|
||||
110
x.c
110
x.c
@@ -14,6 +14,7 @@
|
||||
#include <X11/keysym.h>
|
||||
#include <X11/Xft/Xft.h>
|
||||
#include <X11/XKBlib.h>
|
||||
#include <X11/Xresource.h>
|
||||
|
||||
char *argv0;
|
||||
#include "arg.h"
|
||||
@@ -45,6 +46,19 @@ typedef struct {
|
||||
signed char appcursor; /* application cursor */
|
||||
} Key;
|
||||
|
||||
/* Xresources preferences */
|
||||
enum resource_type {
|
||||
STRING = 0,
|
||||
INTEGER = 1,
|
||||
FLOAT = 2
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
char *name;
|
||||
enum resource_type type;
|
||||
void *dst;
|
||||
} ResourcePref;
|
||||
|
||||
/* X modifiers */
|
||||
#define XK_ANY_MOD UINT_MAX
|
||||
#define XK_NO_MOD 0
|
||||
@@ -59,6 +73,8 @@ static void zoom(const Arg *);
|
||||
static void zoomabs(const Arg *);
|
||||
static void zoomreset(const Arg *);
|
||||
static void ttysend(const Arg *);
|
||||
void kscrollup(const Arg *);
|
||||
void kscrolldown(const Arg *);
|
||||
|
||||
/* config.h for applying patches and the configuration. */
|
||||
#include "config.h"
|
||||
@@ -818,7 +834,7 @@ xloadcols(void)
|
||||
int
|
||||
xgetcolor(int x, unsigned char *r, unsigned char *g, unsigned char *b)
|
||||
{
|
||||
if (!BETWEEN(x, 0, dc.collen))
|
||||
if (!BETWEEN(x, 0, dc.collen - 1))
|
||||
return 1;
|
||||
|
||||
*r = dc.col[x].color.red >> 8;
|
||||
@@ -833,7 +849,7 @@ 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))
|
||||
@@ -859,8 +875,8 @@ xclear(int x1, int y1, int x2, int y2)
|
||||
void
|
||||
xhints(void)
|
||||
{
|
||||
XClassHint class = {opt_name ? opt_name : termname,
|
||||
opt_class ? opt_class : termname};
|
||||
XClassHint class = {opt_name ? opt_name : "st",
|
||||
opt_class ? opt_class : "St"};
|
||||
XWMHints wm = {.flags = InputHint, .input = 1};
|
||||
XSizeHints *sizeh;
|
||||
|
||||
@@ -1131,12 +1147,10 @@ xinit(int cols, int rows)
|
||||
{
|
||||
XGCValues gcvalues;
|
||||
Cursor cursor;
|
||||
Window parent;
|
||||
Window parent, root;
|
||||
pid_t thispid = getpid();
|
||||
XColor xmousefg, xmousebg;
|
||||
|
||||
if (!(xw.dpy = XOpenDisplay(NULL)))
|
||||
die("can't open display\n");
|
||||
xw.scr = XDefaultScreen(xw.dpy);
|
||||
xw.vis = XDefaultVisual(xw.dpy, xw.scr);
|
||||
|
||||
@@ -1168,16 +1182,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));
|
||||
@@ -1617,6 +1634,9 @@ xseticontitle(char *p)
|
||||
XTextProperty prop;
|
||||
DEFAULT(p, opt_title);
|
||||
|
||||
if (p[0] == '\0')
|
||||
p = opt_title;
|
||||
|
||||
if (Xutf8TextListToTextProperty(xw.dpy, &p, 1, XUTF8StringStyle,
|
||||
&prop) != Success)
|
||||
return;
|
||||
@@ -1631,6 +1651,9 @@ xsettitle(char *p)
|
||||
XTextProperty prop;
|
||||
DEFAULT(p, opt_title);
|
||||
|
||||
if (p[0] == '\0')
|
||||
p = opt_title;
|
||||
|
||||
if (Xutf8TextListToTextProperty(xw.dpy, &p, 1, XUTF8StringStyle,
|
||||
&prop) != Success)
|
||||
return;
|
||||
@@ -1833,7 +1856,7 @@ void
|
||||
kpress(XEvent *ev)
|
||||
{
|
||||
XKeyEvent *e = &ev->xkey;
|
||||
KeySym ksym;
|
||||
KeySym ksym = NoSymbol;
|
||||
char buf[64], *customkey;
|
||||
int len;
|
||||
Rune c;
|
||||
@@ -1843,10 +1866,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)) {
|
||||
@@ -2011,6 +2037,59 @@ run(void)
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
resource_load(XrmDatabase db, char *name, enum resource_type rtype, void *dst)
|
||||
{
|
||||
char **sdst = dst;
|
||||
int *idst = dst;
|
||||
float *fdst = dst;
|
||||
|
||||
char fullname[256];
|
||||
char fullclass[256];
|
||||
char *type;
|
||||
XrmValue ret;
|
||||
|
||||
snprintf(fullname, sizeof(fullname), "%s.%s",
|
||||
opt_name ? opt_name : "st", name);
|
||||
snprintf(fullclass, sizeof(fullclass), "%s.%s",
|
||||
opt_class ? opt_class : "St", name);
|
||||
fullname[sizeof(fullname) - 1] = fullclass[sizeof(fullclass) - 1] = '\0';
|
||||
|
||||
XrmGetResource(db, fullname, fullclass, &type, &ret);
|
||||
if (ret.addr == NULL || strncmp("String", type, 64))
|
||||
return 1;
|
||||
|
||||
switch (rtype) {
|
||||
case STRING:
|
||||
*sdst = ret.addr;
|
||||
break;
|
||||
case INTEGER:
|
||||
*idst = strtoul(ret.addr, NULL, 10);
|
||||
break;
|
||||
case FLOAT:
|
||||
*fdst = strtof(ret.addr, NULL);
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
config_init(void)
|
||||
{
|
||||
char *resm;
|
||||
XrmDatabase db;
|
||||
ResourcePref *p;
|
||||
|
||||
XrmInitialize();
|
||||
resm = XResourceManagerString(xw.dpy);
|
||||
if (!resm)
|
||||
return;
|
||||
|
||||
db = XrmGetStringDatabase(resm);
|
||||
for (p = resources; p < resources + LEN(resources); p++)
|
||||
resource_load(db, p->name, p->type, p->dst);
|
||||
}
|
||||
|
||||
void
|
||||
usage(void)
|
||||
{
|
||||
@@ -2084,6 +2163,11 @@ run:
|
||||
|
||||
setlocale(LC_CTYPE, "");
|
||||
XSetLocaleModifiers("");
|
||||
|
||||
if(!(xw.dpy = XOpenDisplay(NULL)))
|
||||
die("Can't open display\n");
|
||||
|
||||
config_init();
|
||||
cols = MAX(cols, 1);
|
||||
rows = MAX(rows, 1);
|
||||
tnew(cols, rows);
|
||||
|
||||
Reference in New Issue
Block a user