15 Commits

Author SHA1 Message Date
98a2dd55b0 add dmenu dark and light variants 2025-10-10 07:30:34 +02:00
634f6cb5ad add copy/paste dmenu prompt and remove empty values from completion list 2025-10-09 22:35:21 +02:00
3c9aef2597 add key to insert text selected with dmenu as terminal input 2025-10-09 21:37:41 +02:00
ffd5e8750d add keys to edit screen content with editor and copy WORD using externalpipe 2025-10-09 08:55:49 +02:00
1a19738a57 agree st-externalpipe with st-scrollback-ringbuffer 2025-10-09 08:07:42 +02:00
a6f61c8b65 apply st-externalpipe-0.8.5.diff 2025-10-09 08:02:57 +02:00
a88f2f16ef update font 2025-10-09 08:00:12 +02:00
Timo Röhling
7cbc44eba5 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).
2025-10-09 07:58:55 +02:00
wael
9fef53395a fix xresources with signal reloading removing arg.h and st.h & remove unneccesary xresources variables(?) 2025-10-09 07:53:45 +02:00
Hiltjo Posthuma
6e97047474 bump version to 0.9.3 2025-08-09 14:35:14 +02:00
Hiltjo Posthuma
5a4666c19e add a few comments 2025-08-09 14:22:28 +02:00
Ayman Bagabas
d6c431859c Support OSC 110, 111, and 112 for resetting colors
This adds support for OSC 110, 111, and 112 escape sequences to reset
the foreground, background, and cursor colors in the terminal. The
changes include handling these sequences in the `strhandle` function of
`st.c`, allowing applications to reset colors to their default values.

The OSC sequences originated from Xterm control sequences and are now
widely used in terminal applications and supported by many terminal
emulators. For applications, this allows them to reset colors to
default values without needing to know the colors beforehand.

Signed-off-by: Ayman Bagabas <ayman.bagabas@gmail.com>
2025-08-09 12:34:01 +02:00
sasha
f114bcedd1 Eat up "CSI 58" sequences
This is used in the wild by systemd systemctl for example and st
misinterpreted it as "blink", because it didn't know "58", then saw "5"
as "blink", and then didn't know "245".

This should print "foo" as normal text:

    printf '\e[58:5:245mfoo\n'
    printf '\e[58:2:50:100:200mfoo\n'
2025-07-27 20:06:54 +02:00
Johannes Altmanninger
98610fcd37 Do not interpret CSI ? u as DECRC
The kitty keyboard protocol docs recommend CSI ? u to query support for
that protocol, see https://sw.kovidgoyal.net/kitty/keyboard-protocol/

For better or worse, fish shell uses this query to work around bugs
in other terminals triggered by requesting that protocol via CSI = 5 u.

Unfortunately, st interprets CSI ? u as DECRC (restore cursor
position). reproduce with 'printf "\x1b[?u"; cat'.

fish could work around this by switching to the alternate screen
before running this query; but that might cause tearing on terminals
that don't support Synchronized Output. I'm not sure.

In the meantime, let's correct our parser.

This adds a redundant else-after-return, for consistency with the
surrounding code.
2025-01-30 17:50:37 +01:00
Markus Rinne
6009e6e25b Clear screen: Fix edge case
With sequence \e[1J, if cursor is on second line, clear the first line.
2024-12-06 13:42:50 +01:00
5 changed files with 566 additions and 138 deletions

View File

@@ -5,9 +5,43 @@
* *
* font: see http://freedesktop.org/software/fontconfig/fontconfig-user.html * font: see http://freedesktop.org/software/fontconfig/fontconfig-user.html
*/ */
static char *font = "Liberation Mono:pixelsize=12:antialias=true:autohint=true"; static char *font = "FiraCode Nerd Font:size=10";
static int borderpx = 2; static int borderpx = 2;
static char *externaleditcmd[] = { "/bin/sh", "-c",
"tmpfile=$(mktemp /tmp/st-edit.XXXXXX)\n"
"trap 'rm \"$tmpfile\"' 0 1 15\n"
"cat > \"$tmpfile\"\n"
"st -e vis \"$tmpfile\"\n",
NULL};
int lightmode = 0;
#define COL_GRAY1 "'#222222'"
#define COL_GRAY2 "'#444444'"
#define COL_GRAY3 "'#bbbbbb'"
#define COL_GRAY4 "'#eeeeee'"
#define COL_CYAN "'#005577'"
#define DMENU_DARK "-l 10 -fn 'FiraCode Nerd Font:size=10' -nb " COL_GRAY1 " -nf " COL_GRAY3 " -sb " COL_CYAN " -sf " COL_GRAY4
#define DMENU_LIGHT "-l 10 -fn 'FiraCode Nerd Font:size=10' -nb " COL_GRAY3 " -nf " COL_GRAY1 " -sb " COL_CYAN " -sf " COL_GRAY4
static char *externalcopydarkcmd[] = { "/bin/sh", "-c",
"sed 's/[ \t][ \t]*/\\n/g' | tac | awk 'BEGIN{x[\"\"]++} !x[$0]++' | dmenu " DMENU_DARK " -w $WINDOWID -p Copy | tr -d '\\n' | vis-clipboard --copy",
NULL};
static char *externalpastedarkcmd[] = { "/bin/sh", "-c",
"sed 's/[ \t][ \t]*/\\n/g' | tac | awk 'BEGIN{x[\"\"]++} !x[$0]++' | dmenu " DMENU_DARK " -w $WINDOWID -p Paste | tr -d '\\n'",
NULL};
static char *externalcopylightcmd[] = { "/bin/sh", "-c",
"sed 's/[ \t][ \t]*/\\n/g' | tac | awk 'BEGIN{x[\"\"]++} !x[$0]++' | dmenu " DMENU_LIGHT " -w $WINDOWID -p Copy | tr -d '\\n' | vis-clipboard --copy",
NULL};
static char *externalpastelightcmd[] = { "/bin/sh", "-c",
"sed 's/[ \t][ \t]*/\\n/g' | tac | awk 'BEGIN{x[\"\"]++} !x[$0]++' | dmenu " DMENU_LIGHT " -w $WINDOWID -p Paste | tr -d '\\n'",
NULL};
/* /*
* What program is execed by st depends of these precedence rules: * What program is execed by st depends of these precedence rules:
* 1: program passed with -e * 1: program passed with -e
@@ -199,8 +233,13 @@ static Shortcut shortcuts[] = {
{ TERMMOD, XK_C, clipcopy, {.i = 0} }, { TERMMOD, XK_C, clipcopy, {.i = 0} },
{ TERMMOD, XK_V, clippaste, {.i = 0} }, { TERMMOD, XK_V, clippaste, {.i = 0} },
{ TERMMOD, XK_Y, selpaste, {.i = 0} }, { TERMMOD, XK_Y, selpaste, {.i = 0} },
{ TERMMOD, XK_E, externalpipe, { .v = externaleditcmd } },
{ TERMMOD, XK_K, externalpipecopy, { 0 } },
{ TERMMOD, XK_I, externalpipepaste, { 0 } },
{ ShiftMask, XK_Insert, selpaste, {.i = 0} }, { ShiftMask, XK_Insert, selpaste, {.i = 0} },
{ TERMMOD, XK_Num_Lock, numlock, {.i = 0} }, { TERMMOD, XK_Num_Lock, numlock, {.i = 0} },
{ ShiftMask, XK_Page_Up, kscrollup, {.i = -1} },
{ ShiftMask, XK_Page_Down, kscrolldown, {.i = -1} },
}; };
/* /*

View File

@@ -1,5 +1,5 @@
# st version # st version
VERSION = 0.9.2 VERSION = 0.9.3
# Customize below to fit your system # Customize below to fit your system

525
st.c
View File

@@ -43,6 +43,10 @@
#define ISCONTROL(c) (ISCONTROLC0(c) || ISCONTROLC1(c)) #define ISCONTROL(c) (ISCONTROLC0(c) || ISCONTROLC1(c))
#define ISDELIM(u) (u && wcschr(worddelimiters, u)) #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 { enum term_mode {
MODE_WRAP = 1 << 0, MODE_WRAP = 1 << 0,
MODE_INSERT = 1 << 1, MODE_INSERT = 1 << 1,
@@ -109,12 +113,21 @@ typedef struct {
int alt; int alt;
} Selection; } 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 */ /* Internal representation of the screen */
typedef struct { typedef struct {
int row; /* nb row */ int row; /* nb row */
int col; /* nb col */ int col; /* nb col */
Line *line; /* screen */ LineBuffer screen[2]; /* screen and alternate screen */
Line *alt; /* alternate screen */ int linelen; /* allocated line length */
int *dirty; /* dirtyness of lines */ int *dirty; /* dirtyness of lines */
TCursor c; /* cursor */ TCursor c; /* cursor */
int ocx; /* old cursor col */ int ocx; /* old cursor col */
@@ -203,6 +216,8 @@ static void tdeftran(char);
static void tstrsequence(uchar); static void tstrsequence(uchar);
static void drawregion(int, int, int, int); static void drawregion(int, int, int, int);
static void clearline(Line, Glyph, int, int);
static Line ensureline(Line);
static void selnormalize(void); static void selnormalize(void);
static void selscroll(int, int); static void selscroll(int, int);
@@ -408,11 +423,12 @@ int
tlinelen(int y) tlinelen(int y)
{ {
int i = term.col; 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; return i;
while (i > 0 && term.line[y][i - 1].u == ' ') while (i > 0 && line[i - 1].u == ' ')
--i; --i;
return 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 * Snap around if the word wraps around at the end or
* beginning of a line. * beginning of a line.
*/ */
prevgp = &term.line[*y][*x]; prevgp = &TLINE(*y)[*x];
prevdelim = ISDELIM(prevgp->u); prevdelim = ISDELIM(prevgp->u);
for (;;) { for (;;) {
newx = *x + direction; newx = *x + direction;
@@ -536,14 +552,14 @@ selsnap(int *x, int *y, int direction)
yt = *y, xt = *x; yt = *y, xt = *x;
else else
yt = newy, xt = newx; yt = newy, xt = newx;
if (!(term.line[yt][xt].mode & ATTR_WRAP)) if (!(TLINE(yt)[xt].mode & ATTR_WRAP))
break; break;
} }
if (newx >= tlinelen(newy)) if (newx >= tlinelen(newy))
break; break;
gp = &term.line[newy][newx]; gp = &TLINE(newy)[newx];
delim = ISDELIM(gp->u); delim = ISDELIM(gp->u);
if (!(gp->mode & ATTR_WDUMMY) && (delim != prevdelim if (!(gp->mode & ATTR_WDUMMY) && (delim != prevdelim
|| (delim && gp->u != prevgp->u))) || (delim && gp->u != prevgp->u)))
@@ -564,14 +580,14 @@ selsnap(int *x, int *y, int direction)
*x = (direction < 0) ? 0 : term.col - 1; *x = (direction < 0) ? 0 : term.col - 1;
if (direction < 0) { if (direction < 0) {
for (; *y > 0; *y += direction) { for (; *y > 0; *y += direction) {
if (!(term.line[*y-1][term.col-1].mode if (!(TLINE(*y-1)[term.col-1].mode
& ATTR_WRAP)) { & ATTR_WRAP)) {
break; break;
} }
} }
} else if (direction > 0) { } else if (direction > 0) {
for (; *y < term.row-1; *y += direction) { for (; *y < term.row-1; *y += direction) {
if (!(term.line[*y][term.col-1].mode if (!(TLINE(*y)[term.col-1].mode
& ATTR_WRAP)) { & ATTR_WRAP)) {
break; break;
} }
@@ -602,13 +618,13 @@ getsel(void)
} }
if (sel.type == SEL_RECTANGULAR) { if (sel.type == SEL_RECTANGULAR) {
gp = &term.line[y][sel.nb.x]; gp = &TLINE(y)[sel.nb.x];
lastx = sel.ne.x; lastx = sel.ne.x;
} else { } 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; 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 == ' ') while (last >= gp && last->u == ' ')
--last; --last;
@@ -718,8 +734,14 @@ sigchld(int a)
if ((p = waitpid(pid, &stat, WNOHANG)) < 0) if ((p = waitpid(pid, &stat, WNOHANG)) < 0)
die("waiting for pid %hd failed: %s\n", pid, strerror(errno)); die("waiting for pid %hd failed: %s\n", pid, strerror(errno));
if (pid != p) if (pid != p) {
if (p == 0 && wait(&stat) < 0)
die("wait: %s\n", strerror(errno));
/* reinstall sigchld handler */
signal(SIGCHLD, sigchld);
return; return;
}
if (WIFEXITED(stat) && WEXITSTATUS(stat)) if (WIFEXITED(stat) && WEXITSTATUS(stat))
die("child exited with status %d\n", WEXITSTATUS(stat)); die("child exited with status %d\n", WEXITSTATUS(stat));
@@ -803,7 +825,7 @@ ttynew(const char *line, char *cmd, const char *out, char **args)
break; break;
default: default:
#ifdef __OpenBSD__ #ifdef __OpenBSD__
if (pledge("stdio rpath tty proc", NULL) == -1) if (pledge("stdio rpath tty proc exec", NULL) == -1)
die("pledge\n"); die("pledge\n");
#endif #endif
close(s); close(s);
@@ -949,12 +971,15 @@ int
tattrset(int attr) tattrset(int attr)
{ {
int i, j; int i, j;
int y = TLINEOFFSET(0);
for (i = 0; i < term.row-1; i++) { for (i = 0; i < term.row-1; i++) {
Line line = TSCREEN.buffer[y];
for (j = 0; j < term.col-1; j++) { for (j = 0; j < term.col-1; j++) {
if (term.line[i][j].mode & attr) if (line[j].mode & attr)
return 1; return 1;
} }
y = (y+1) % TSCREEN.size;
} }
return 0; return 0;
@@ -976,14 +1001,17 @@ void
tsetdirtattr(int attr) tsetdirtattr(int attr)
{ {
int i, j; int i, j;
int y = TLINEOFFSET(0);
for (i = 0; i < term.row-1; i++) { for (i = 0; i < term.row-1; i++) {
Line line = TSCREEN.buffer[y];
for (j = 0; j < term.col-1; j++) { for (j = 0; j < term.col-1; j++) {
if (term.line[i][j].mode & attr) { if (line[j].mode & attr) {
tsetdirt(i, i); tsetdirt(i, i);
break; break;
} }
} }
y = (y+1) % TSCREEN.size;
} }
} }
@@ -996,27 +1024,19 @@ tfulldirt(void)
void void
tcursor(int mode) tcursor(int mode)
{ {
static TCursor c[2];
int alt = IS_SET(MODE_ALTSCREEN);
if (mode == CURSOR_SAVE) { if (mode == CURSOR_SAVE) {
c[alt] = term.c; TSCREEN.sc = term.c;
} else if (mode == CURSOR_LOAD) { } else if (mode == CURSOR_LOAD) {
term.c = c[alt]; term.c = TSCREEN.sc;
tmoveto(c[alt].x, c[alt].y); tmoveto(term.c.x, term.c.y);
} }
} }
void void
treset(void) treset(void)
{ {
uint i; int i, j;
Glyph g = (Glyph){ .fg = defaultfg, .bg = defaultbg};
term.c = (TCursor){{
.mode = ATTR_NULL,
.fg = defaultfg,
.bg = defaultbg
}, .x = 0, .y = 0, .state = CURSOR_DEFAULT};
memset(term.tabs, 0, term.col * sizeof(*term.tabs)); memset(term.tabs, 0, term.col * sizeof(*term.tabs));
for (i = tabspaces; i < term.col; i += tabspaces) for (i = tabspaces; i < term.col; i += tabspaces)
@@ -1028,17 +1048,37 @@ treset(void)
term.charset = 0; term.charset = 0;
for (i = 0; i < 2; i++) { for (i = 0; i < 2; i++) {
tmoveto(0, 0); term.screen[i].sc = (TCursor){{
tcursor(CURSOR_SAVE); .fg = defaultfg,
tclearregion(0, 0, term.col-1, term.row-1); .bg = defaultbg
tswapscreen(); }};
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 void
tnew(int col, int row) 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); tresize(col, row);
treset(); treset();
} }
@@ -1046,14 +1086,42 @@ tnew(int col, int row)
void void
tswapscreen(void) tswapscreen(void)
{ {
Line *tmp = term.line;
term.line = term.alt;
term.alt = tmp;
term.mode ^= MODE_ALTSCREEN; term.mode ^= MODE_ALTSCREEN;
tfulldirt(); 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 void
tscrolldown(int orig, int n) tscrolldown(int orig, int n)
{ {
@@ -1062,15 +1130,29 @@ tscrolldown(int orig, int n)
LIMIT(n, 0, term.bot-orig+1); LIMIT(n, 0, term.bot-orig+1);
tsetdirt(orig, term.bot-n); /* Ensure that lines are allocated */
tclearregion(0, term.bot-n+1, term.col-1, term.bot); 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); selscroll(orig, n);
} }
@@ -1082,15 +1164,29 @@ tscrollup(int orig, int n)
LIMIT(n, 0, term.bot-orig+1); LIMIT(n, 0, term.bot-orig+1);
tclearregion(0, orig, term.col-1, orig+n-1); /* Ensure that lines are allocated */
tsetdirt(orig+n, term.bot); 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); selscroll(orig, -n);
} }
@@ -1197,6 +1293,7 @@ tsetchar(Rune u, const Glyph *attr, int x, int y)
"", "", "", "", "", "", "", "", /* p - w */ "", "", "", "", "", "", "", "", /* p - w */
"", "", "", "π", "", "£", "·", /* x - ~ */ "", "", "", "π", "", "£", "·", /* x - ~ */
}; };
Line line = TLINE(y);
/* /*
* The table is proudly stolen from rxvt. * The table is proudly stolen from rxvt.
@@ -1205,25 +1302,25 @@ tsetchar(Rune u, const Glyph *attr, int x, int y)
BETWEEN(u, 0x41, 0x7e) && vt100_0[u - 0x41]) BETWEEN(u, 0x41, 0x7e) && vt100_0[u - 0x41])
utf8decode(vt100_0[u - 0x41], &u, UTF_SIZ); 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) { if (x+1 < term.col) {
term.line[y][x+1].u = ' '; line[x+1].u = ' ';
term.line[y][x+1].mode &= ~ATTR_WDUMMY; line[x+1].mode &= ~ATTR_WDUMMY;
} }
} else if (term.line[y][x].mode & ATTR_WDUMMY) { } else if (line[x].mode & ATTR_WDUMMY) {
term.line[y][x-1].u = ' '; line[x-1].u = ' ';
term.line[y][x-1].mode &= ~ATTR_WIDE; line[x-1].mode &= ~ATTR_WIDE;
} }
term.dirty[y] = 1; term.dirty[y] = 1;
term.line[y][x] = *attr; line[x] = *attr;
term.line[y][x].u = u; line[x].u = u;
} }
void void
tclearregion(int x1, int y1, int x2, int y2) tclearregion(int x1, int y1, int x2, int y2)
{ {
int x, y, temp; int x, y, L, S, temp;
Glyph *gp; Glyph *gp;
if (x1 > x2) if (x1 > x2)
@@ -1231,15 +1328,16 @@ tclearregion(int x1, int y1, int x2, int y2)
if (y1 > y2) if (y1 > y2)
temp = y1, y1 = y2, y2 = temp; temp = y1, y1 = y2, y2 = temp;
LIMIT(x1, 0, term.col-1); LIMIT(x1, 0, term.linelen-1);
LIMIT(x2, 0, term.col-1); LIMIT(x2, 0, term.linelen-1);
LIMIT(y1, 0, term.row-1); LIMIT(y1, 0, term.row-1);
LIMIT(y2, 0, term.row-1); LIMIT(y2, 0, term.row-1);
L = TLINEOFFSET(y1);
for (y = y1; y <= y2; y++) { for (y = y1; y <= y2; y++) {
term.dirty[y] = 1; term.dirty[y] = 1;
for (x = x1; x <= x2; x++) { for (x = x1; x <= x2; x++) {
gp = &term.line[y][x]; gp = &TSCREEN.buffer[L][x];
if (selected(x, y)) if (selected(x, y))
selclear(); selclear();
gp->fg = term.c.attr.fg; gp->fg = term.c.attr.fg;
@@ -1247,6 +1345,7 @@ tclearregion(int x1, int y1, int x2, int y2)
gp->mode = 0; gp->mode = 0;
gp->u = ' '; gp->u = ' ';
} }
L = (L + 1) % TSCREEN.size;
} }
} }
@@ -1261,7 +1360,7 @@ tdeletechar(int n)
dst = term.c.x; dst = term.c.x;
src = term.c.x + n; src = term.c.x + n;
size = term.col - src; size = term.col - src;
line = term.line[term.c.y]; line = TLINE(term.c.y);
memmove(&line[dst], &line[src], size * sizeof(Glyph)); memmove(&line[dst], &line[src], size * sizeof(Glyph));
tclearregion(term.col-n, term.c.y, term.col-1, term.c.y); tclearregion(term.col-n, term.c.y, term.col-1, term.c.y);
@@ -1278,7 +1377,7 @@ tinsertblank(int n)
dst = term.c.x + n; dst = term.c.x + n;
src = term.c.x; src = term.c.x;
size = term.col - dst; size = term.col - dst;
line = term.line[term.c.y]; line = TLINE(term.c.y);
memmove(&line[dst], &line[src], size * sizeof(Glyph)); memmove(&line[dst], &line[src], size * sizeof(Glyph));
tclearregion(src, term.c.y, dst - 1, term.c.y); tclearregion(src, term.c.y, dst - 1, term.c.y);
@@ -1420,16 +1519,22 @@ tsetattr(const int *attr, int l)
if ((idx = tdefcolor(attr, &i, l)) >= 0) if ((idx = tdefcolor(attr, &i, l)) >= 0)
term.c.attr.fg = idx; term.c.attr.fg = idx;
break; break;
case 39: case 39: /* set foreground color to default */
term.c.attr.fg = defaultfg; term.c.attr.fg = defaultfg;
break; break;
case 48: case 48:
if ((idx = tdefcolor(attr, &i, l)) >= 0) if ((idx = tdefcolor(attr, &i, l)) >= 0)
term.c.attr.bg = idx; term.c.attr.bg = idx;
break; break;
case 49: case 49: /* set background color to default */
term.c.attr.bg = defaultbg; term.c.attr.bg = defaultbg;
break; 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: default:
if (BETWEEN(attr[i], 30, 37)) { if (BETWEEN(attr[i], 30, 37)) {
term.c.attr.fg = attr[i] - 30; term.c.attr.fg = attr[i] - 30;
@@ -1526,7 +1631,7 @@ tsetmode(int priv, int set, const int *args, int narg)
case 1006: /* 1006: extended reporting mode */ case 1006: /* 1006: extended reporting mode */
xsetmode(set, MODE_MOUSESGR); xsetmode(set, MODE_MOUSESGR);
break; break;
case 1034: case 1034: /* 1034: enable 8-bit mode for keyboard input */
xsetmode(set, MODE_8BIT); xsetmode(set, MODE_8BIT);
break; break;
case 1049: /* swap screen & set/restore cursor as xterm */ case 1049: /* swap screen & set/restore cursor as xterm */
@@ -1534,8 +1639,8 @@ tsetmode(int priv, int set, const int *args, int narg)
break; break;
tcursor((set) ? CURSOR_SAVE : CURSOR_LOAD); tcursor((set) ? CURSOR_SAVE : CURSOR_LOAD);
/* FALLTHROUGH */ /* FALLTHROUGH */
case 47: /* swap screen */ case 47: /* swap screen buffer */
case 1047: case 1047: /* swap screen buffer */
if (!allowaltscreen) if (!allowaltscreen)
break; break;
alt = IS_SET(MODE_ALTSCREEN); alt = IS_SET(MODE_ALTSCREEN);
@@ -1548,7 +1653,7 @@ tsetmode(int priv, int set, const int *args, int narg)
if (*args != 1049) if (*args != 1049)
break; break;
/* FALLTHROUGH */ /* FALLTHROUGH */
case 1048: case 1048: /* save/restore cursor (like DECSC/DECRC) */
tcursor((set) ? CURSOR_SAVE : CURSOR_LOAD); tcursor((set) ? CURSOR_SAVE : CURSOR_LOAD);
break; break;
case 2004: /* 2004: bracketed paste mode */ case 2004: /* 2004: bracketed paste mode */
@@ -1705,7 +1810,7 @@ csihandle(void)
} }
break; break;
case 1: /* above */ 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, 0, term.col-1, term.c.y-1);
tclearregion(0, term.c.y, term.c.x, term.c.y); tclearregion(0, term.c.y, term.c.x, term.c.y);
break; break;
@@ -1801,7 +1906,11 @@ csihandle(void)
tcursor(CURSOR_SAVE); tcursor(CURSOR_SAVE);
break; break;
case 'u': /* DECRC -- Restore cursor position (ANSI.SYS) */ case 'u': /* DECRC -- Restore cursor position (ANSI.SYS) */
tcursor(CURSOR_LOAD); if (csiescseq.priv) {
goto unknown;
} else {
tcursor(CURSOR_LOAD);
}
break; break;
case ' ': case ' ':
switch (csiescseq.mode[1]) { switch (csiescseq.mode[1]) {
@@ -1903,7 +2012,7 @@ strhandle(void)
if (narg > 1) if (narg > 1)
xsettitle(strescseq.args[1]); xsettitle(strescseq.args[1]);
return; return;
case 52: case 52: /* manipulate selection data */
if (narg > 2 && allowwindowops) { if (narg > 2 && allowwindowops) {
dec = base64dec(strescseq.args[2]); dec = base64dec(strescseq.args[2]);
if (dec) { if (dec) {
@@ -1914,9 +2023,9 @@ strhandle(void)
} }
} }
return; return;
case 10: case 10: /* set dynamic VT100 text foreground color */
case 11: case 11: /* set dynamic VT100 text background color */
case 12: case 12: /* set dynamic text cursor color */
if (narg < 2) if (narg < 2)
break; break;
p = strescseq.args[1]; p = strescseq.args[1];
@@ -1957,6 +2066,19 @@ strhandle(void)
tfulldirt(); tfulldirt();
} }
return; 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; break;
case 'k': /* old title set compatibility */ case 'k': /* old title set compatibility */
@@ -1994,6 +2116,111 @@ strparse(void)
} }
} }
void
externalpipeinout(const Arg *arg, void (*processout)(int fildes))
{
int to[2], from[2];
char buf[UTF_SIZ];
void (*oldsigpipe)(int);
Glyph *bp, *end;
int lastpos, n, newline;
if (pipe(to) == -1)
return;
if (processout != NULL && pipe(from) == -1)
return;
switch (fork()) {
case -1:
close(to[0]);
close(to[1]);
if (processout != NULL) {
close(from[0]);
close(from[1]);
}
return;
case 0:
dup2(to[0], STDIN_FILENO);
close(to[0]);
close(to[1]);
if (processout != NULL) {
dup2(from[1], STDOUT_FILENO);
close(from[0]);
close(from[1]);
}
execvp(((char **)arg->v)[0], (char **)arg->v);
fprintf(stderr, "st: execvp %s\n", ((char **)arg->v)[0]);
perror("failed");
exit(0);
}
close(to[0]);
if (processout != NULL)
close(from[1]);
/* ignore sigpipe for now, in case child exists early */
oldsigpipe = signal(SIGPIPE, SIG_IGN);
newline = 0;
for (n = 0; n < term.row; n++) {
bp = TLINE(n);
lastpos = MIN(tlinelen(n) + 1, term.col) - 1;
if (lastpos < 0)
break;
end = &bp[lastpos + 1];
for (; bp < end; ++bp)
if (xwrite(to[1], buf, utf8encode(bp->u, buf)) < 0)
break;
if ((newline = TLINE(n)[lastpos].mode & ATTR_WRAP))
continue;
if (xwrite(to[1], "\n", 1) < 0)
break;
newline = 0;
}
if (newline)
(void)xwrite(to[1], "\n", 1);
close(to[1]);
if (processout != NULL) {
processout(from[0]);
close(from[0]);
}
/* restore */
signal(SIGPIPE, oldsigpipe);
}
void
externalpipe(const Arg *arg)
{
externalpipeinout(arg, NULL);
}
void
ttycopy(int fildes)
{
char buf[256];
int len;
len = read(fildes, buf, sizeof(buf));
if (len > 0 && len < sizeof(buf)) {
buf[len] = '\0';
ttywrite(buf, len, 1);
}
}
void
externalpipepaste(const Arg *)
{
Arg arg;
arg.v = externalpastecmd();
externalpipeinout(&arg, ttycopy);
}
void
externalpipecopy(const Arg *)
{
Arg arg;
arg.v = externalcopycmd();
externalpipeinout(&arg, NULL);
}
void void
strdump(void) strdump(void)
{ {
@@ -2082,7 +2309,7 @@ tdumpline(int n)
char buf[UTF_SIZ]; char buf[UTF_SIZ];
const Glyph *bp, *end; const Glyph *bp, *end;
bp = &term.line[n][0]; bp = &TLINE(n)[0];
end = &bp[MIN(tlinelen(n), term.col) - 1]; end = &bp[MIN(tlinelen(n), term.col) - 1];
if (bp != end || bp->u != ' ') { if (bp != end || bp->u != ' ') {
for ( ; bp <= end; ++bp) for ( ; bp <= end; ++bp)
@@ -2469,11 +2696,11 @@ check_control_code:
if (selected(term.c.x, term.c.y)) if (selected(term.c.x, term.c.y))
selclear(); 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)) { if (IS_SET(MODE_WRAP) && (term.c.state & CURSOR_WRAPNEXT)) {
gp->mode |= ATTR_WRAP; gp->mode |= ATTR_WRAP;
tnewline(1); 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) {
@@ -2486,7 +2713,7 @@ check_control_code:
tnewline(1); tnewline(1);
else else
tmoveto(term.col - width, term.c.y); 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); tsetchar(u, &term.c.attr, term.c.x, term.c.y);
@@ -2517,6 +2744,11 @@ twrite(const char *buf, int buflen, int show_ctrl)
Rune u; Rune u;
int n; int n;
if (TSCREEN.off) {
TSCREEN.off = 0;
tfulldirt();
}
for (n = 0; n < buflen; n += charsize) { for (n = 0; n < buflen; n += charsize) {
if (IS_SET(MODE_UTF8)) { if (IS_SET(MODE_UTF8)) {
/* process a complete utf8 char */ /* process a complete utf8 char */
@@ -2543,56 +2775,85 @@ twrite(const char *buf, int buflen, int show_ctrl)
} }
void void
tresize(int col, int row) clearline(Line line, Glyph g, int x, int xend)
{ {
int i; 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 minrow = MIN(row, term.row);
int mincol = MIN(col, term.col); int mincol = MIN(col, term.col);
int linelen = MAX(col, term.linelen);
int *bp; int *bp;
TCursor c;
if (col < 1 || row < 1) { if (col < 1 || row < 1 || row > HISTSIZE) {
fprintf(stderr, fprintf(stderr,
"tresize: error resizing to %dx%d\n", col, row); "tresize: error resizing to %dx%d\n", col, row);
return; return;
} }
/* /* Shift buffer to keep the cursor where we expect it */
* slide screen to keep cursor where we expect it - if (row <= term.c.y) {
* tscrollup would work here, but we can optimize to term.screen[0].cur = (term.screen[0].cur - row + term.c.y + 1) % term.screen[0].size;
* 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]);
} }
/* ensure that both src and dst are not NULL */
if (i > 0) { /* Resize and clear line buffers as needed */
memmove(term.line, term.line + i, row * sizeof(Line)); if (linelen > term.linelen) {
memmove(term.alt, term.alt + i, row * sizeof(Line)); 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);
}
} }
for (i += row; i < term.row; i++) { /* Allocate all visible lines for regular line buffer */
free(term.line[i]); for (j = term.screen[0].cur, i = 0; i < row; ++i, j = (j + 1) % term.screen[0].size)
free(term.alt[i]); {
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 */ /* 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.dirty = xrealloc(term.dirty, row * sizeof(*term.dirty));
term.tabs = xrealloc(term.tabs, col * sizeof(*term.tabs)); term.tabs = xrealloc(term.tabs, col * sizeof(*term.tabs));
/* resize each row to new width, zero-pad if needed */ /* fix tabstops */
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));
}
if (col > term.col) { if (col > term.col) {
bp = term.tabs + term.col; bp = term.tabs + term.col;
@@ -2602,26 +2863,16 @@ tresize(int col, int row)
for (bp += tabspaces; bp < term.tabs + col; bp += tabspaces) for (bp += tabspaces; bp < term.tabs + col; bp += tabspaces)
*bp = 1; *bp = 1;
} }
/* update terminal size */ /* update terminal size */
term.col = col; term.col = col;
term.row = row; term.row = row;
term.linelen = linelen;
/* reset scrolling region */ /* reset scrolling region */
tsetscroll(0, row-1); tsetscroll(0, row-1);
/* make use of the LIMIT in tmoveto */ /* make use of the LIMIT in tmoveto */
tmoveto(term.c.x, term.c.y); tmoveto(term.c.x, term.c.y);
/* Clearing both screens (it makes dirty all lines) */ tfulldirt();
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;
} }
void void
@@ -2633,14 +2884,15 @@ resettitle(void)
void void
drawregion(int x1, int y1, int x2, int y2) drawregion(int x1, int y1, int x2, int y2)
{ {
int y; int y, L;
L = TLINEOFFSET(y1);
for (y = y1; y < y2; y++) { for (y = y1; y < y2; y++) {
if (!term.dirty[y]) if (term.dirty[y]) {
continue; term.dirty[y] = 0;
xdrawline(TSCREEN.buffer[L], x1, y, x2);
term.dirty[y] = 0; }
xdrawline(term.line[y], x1, y, x2); L = (L + 1) % TSCREEN.size;
} }
} }
@@ -2655,14 +2907,15 @@ draw(void)
/* adjust cursor position */ /* adjust cursor position */
LIMIT(term.ocx, 0, term.col-1); LIMIT(term.ocx, 0, term.col-1);
LIMIT(term.ocy, 0, term.row-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--; term.ocx--;
if (term.line[term.c.y][cx].mode & ATTR_WDUMMY) if (TLINE(term.c.y)[cx].mode & ATTR_WDUMMY)
cx--; cx--;
drawregion(0, 0, term.col, term.row); drawregion(0, 0, term.col, term.row);
xdrawcursor(cx, term.c.y, term.line[term.c.y][cx], if (TSCREEN.off == 0)
term.ocx, term.ocy, term.line[term.ocy][term.ocx]); xdrawcursor(cx, term.c.y, TLINE(term.c.y)[cx],
term.ocx, term.ocy, TLINE(term.ocy)[term.ocx]);
term.ocx = cx; term.ocx = cx;
term.ocy = term.c.y; term.ocy = term.c.y;
xfinishdraw(); xfinishdraw();

8
st.h
View File

@@ -19,6 +19,7 @@
#define TRUECOLOR(r,g,b) (1 << 24 | (r) << 16 | (g) << 8 | (b)) #define TRUECOLOR(r,g,b) (1 << 24 | (r) << 16 | (g) << 8 | (b))
#define IS_TRUECOL(x) (1 << 24 & (x)) #define IS_TRUECOL(x) (1 << 24 & (x))
#define HISTSIZE 2000
enum glyph_attribute { enum glyph_attribute {
ATTR_NULL = 0, ATTR_NULL = 0,
@@ -81,6 +82,9 @@ void die(const char *, ...);
void redraw(void); void redraw(void);
void draw(void); void draw(void);
void externalpipe(const Arg *);
void externalpipecopy(const Arg *);
void externalpipepaste(const Arg *);
void printscreen(const Arg *); void printscreen(const Arg *);
void printsel(const Arg *); void printsel(const Arg *);
void sendbreak(const Arg *); void sendbreak(const Arg *);
@@ -119,8 +123,12 @@ extern char *vtiden;
extern wchar_t *worddelimiters; extern wchar_t *worddelimiters;
extern int allowaltscreen; extern int allowaltscreen;
extern int allowwindowops; extern int allowwindowops;
extern int lightmode;
extern char *termname; extern char *termname;
extern unsigned int tabspaces; extern unsigned int tabspaces;
extern unsigned int defaultfg; extern unsigned int defaultfg;
extern unsigned int defaultbg; extern unsigned int defaultbg;
extern unsigned int defaultcs; extern unsigned int defaultcs;
char **externalcopycmd();
char **externalpastecmd();

128
x.c
View File

@@ -14,6 +14,7 @@
#include <X11/keysym.h> #include <X11/keysym.h>
#include <X11/Xft/Xft.h> #include <X11/Xft/Xft.h>
#include <X11/XKBlib.h> #include <X11/XKBlib.h>
#include <X11/Xresource.h>
char *argv0; char *argv0;
#include "arg.h" #include "arg.h"
@@ -59,10 +60,22 @@ static void zoom(const Arg *);
static void zoomabs(const Arg *); static void zoomabs(const Arg *);
static void zoomreset(const Arg *); static void zoomreset(const Arg *);
static void ttysend(const Arg *); static void ttysend(const Arg *);
void kscrollup(const Arg *);
void kscrolldown(const Arg *);
/* config.h for applying patches and the configuration. */ /* config.h for applying patches and the configuration. */
#include "config.h" #include "config.h"
char **externalcopycmd()
{
return (lightmode) ? externalcopylightcmd : externalcopydarkcmd;
}
char **externalpastecmd()
{
return (lightmode) ? externalpastelightcmd : externalpastedarkcmd;
}
/* XEMBED messages */ /* XEMBED messages */
#define XEMBED_FOCUS_IN 4 #define XEMBED_FOCUS_IN 4
#define XEMBED_FOCUS_OUT 5 #define XEMBED_FOCUS_OUT 5
@@ -2023,6 +2036,119 @@ run(void)
} }
} }
#define XRESOURCE_LOAD_META(NAME) \
if(!XrmGetResource(xrdb, "st." NAME, "st." NAME, &type, &ret)) \
XrmGetResource(xrdb, "*." NAME, "*." NAME, &type, &ret); \
if (ret.addr != NULL && !strncmp("String", type, 64))
#define XRESOURCE_LOAD_STRING(NAME, DST) \
XRESOURCE_LOAD_META(NAME) \
DST = ret.addr;
#define XRESOURCE_LOAD_CHAR(NAME, DST) \
XRESOURCE_LOAD_META(NAME) \
DST = ret.addr[0];
#define XRESOURCE_LOAD_INTEGER(NAME, DST) \
XRESOURCE_LOAD_META(NAME) \
DST = strtoul(ret.addr, NULL, 10);
#define XRESOURCE_LOAD_FLOAT(NAME, DST) \
XRESOURCE_LOAD_META(NAME) \
DST = strtof(ret.addr, NULL);
void
xrdb_load(void)
{
/* XXX */
char *xrm;
char *type;
XrmDatabase xrdb;
XrmValue ret;
Display *dpy;
if(!(dpy = XOpenDisplay(NULL)))
die("Can't open display\n");
XrmInitialize();
xrm = XResourceManagerString(dpy);
if (xrm != NULL) {
xrdb = XrmGetStringDatabase(xrm);
/* handling colors here without macros to do via loop. */
int i = 0;
char loadValue[12] = "";
for (i = 0; i < 256; i++)
{
sprintf(loadValue, "%s%d", "st.color", i);
if(!XrmGetResource(xrdb, loadValue, loadValue, &type, &ret))
{
sprintf(loadValue, "%s%d", "*.color", i);
if (!XrmGetResource(xrdb, loadValue, loadValue, &type, &ret))
/* reset if not found (unless in range for defaults). */
if (i > 15)
colorname[i] = NULL;
}
if (ret.addr != NULL && !strncmp("String", type, 64))
colorname[i] = ret.addr;
}
XRESOURCE_LOAD_STRING("foreground", colorname[defaultfg]);
XRESOURCE_LOAD_STRING("background", colorname[defaultbg]);
XRESOURCE_LOAD_STRING("cursorColor", colorname[defaultcs])
else {
// this looks confusing because we are chaining off of the if
// in the macro. probably we should be wrapping everything blocks
// so this isn't possible...
defaultcs = defaultfg;
}
XRESOURCE_LOAD_STRING("reverse-cursor", colorname[defaultrcs])
else {
// see above.
defaultrcs = defaultbg;
}
XRESOURCE_LOAD_STRING("font", font);
XRESOURCE_LOAD_STRING("termname", termname);
XRESOURCE_LOAD_INTEGER("blinktimeout", blinktimeout);
XRESOURCE_LOAD_INTEGER("bellvolume", bellvolume);
XRESOURCE_LOAD_INTEGER("borderpx", borderpx);
XRESOURCE_LOAD_INTEGER("cursorshape", cursorshape);
XRESOURCE_LOAD_INTEGER("lightmode", lightmode);
XRESOURCE_LOAD_FLOAT("cwscale", cwscale);
XRESOURCE_LOAD_FLOAT("chscale", chscale);
}
XFlush(dpy);
}
void
reload(int sig)
{
xrdb_load();
/* colors, fonts */
xloadcols();
xunloadfonts();
xloadfonts(font, 0);
/* pretend the window just got resized */
cresize(win.w, win.h);
redraw();
/* triggers re-render if we're visible. */
ttywrite("\033[O", 3, 1);
signal(SIGUSR1, reload);
}
void void
usage(void) usage(void)
{ {
@@ -2096,6 +2222,8 @@ run:
setlocale(LC_CTYPE, ""); setlocale(LC_CTYPE, "");
XSetLocaleModifiers(""); XSetLocaleModifiers("");
xrdb_load();
signal(SIGUSR1, reload);
cols = MAX(cols, 1); cols = MAX(cols, 1);
rows = MAX(rows, 1); rows = MAX(rows, 1);
tnew(cols, rows); tnew(cols, rows);