Added mouse scroll

This commit is contained in:
Linux User 2022-08-16 22:29:24 +00:00
parent 024630e378
commit 9726db9903
8 changed files with 282 additions and 138 deletions

View File

@ -6,12 +6,14 @@
* font: see http://freedesktop.org/software/fontconfig/fontconfig-user.html * font: see http://freedesktop.org/software/fontconfig/fontconfig-user.html
*/ */
static char *font = "Ubuntu Mono:pixelsize=12:antialias=true:autohint=true"; #define FONTSIZE "14"
static char *font = "Ubuntu Mono:pixelsize="FONTSIZE":antialias=true:autohint=true";
static char *font2[] = { static char *font2[] = {
"Ubuntu Mono:pixelsize=12:antialias=true:autohint=true", "Ubuntu Mono:pixelsize="FONTSIZE":antialias=true:autohint=true",
"Font Awesome 6 Free Solid:pixelsize=12:antialias=true:autohint=true" "Font Awesome 6 Free Solid:pixelsize="FONTSIZE":antialias=true:autohint=true"
}; };
static int borderpx = 2; static int borderpx = 10;
/* /*
* What program is execed by st depends of these precedence rules: * What program is execed by st depends of these precedence rules:
@ -181,6 +183,8 @@ static uint forcemousemod = ShiftMask;
*/ */
static MouseShortcut mshortcuts[] = { static MouseShortcut mshortcuts[] = {
/* mask button function argument release */ /* mask button function argument release */
{ XK_ANY_MOD, Button4, kscrollup, {.i = 1} },
{ XK_ANY_MOD, Button5, kscrolldown, {.i = 1} },
{ XK_ANY_MOD, Button2, selpaste, {.i = 0}, 1 }, { XK_ANY_MOD, Button2, selpaste, {.i = 0}, 1 },
{ ShiftMask, Button4, ttysend, {.s = "\033[5;2~"} }, { ShiftMask, Button4, ttysend, {.s = "\033[5;2~"} },
{ XK_ANY_MOD, Button4, ttysend, {.s = "\031"} }, { XK_ANY_MOD, Button4, ttysend, {.s = "\031"} },
@ -206,6 +210,8 @@ static Shortcut shortcuts[] = {
{ TERMMOD, XK_Y, selpaste, {.i = 0} }, { TERMMOD, XK_Y, selpaste, {.i = 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

@ -6,12 +6,14 @@
* font: see http://freedesktop.org/software/fontconfig/fontconfig-user.html * font: see http://freedesktop.org/software/fontconfig/fontconfig-user.html
*/ */
static char *font = "Ubuntu Mono:pixelsize=12:antialias=true:autohint=true"; #define FONTSIZE "14"
static char *font = "Ubuntu Mono:pixelsize="FONTSIZE":antialias=true:autohint=true";
static char *font2[] = { static char *font2[] = {
"Ubuntu Mono:pixelsize=12:antialias=true:autohint=true", "Ubuntu Mono:pixelsize="FONTSIZE":antialias=true:autohint=true",
"Font Awesome 6 Free Solid:pixelsize=12:antialias=true:autohint=true" "Font Awesome 6 Free Solid:pixelsize="FONTSIZE":antialias=true:autohint=true"
}; };
static int borderpx = 2; static int borderpx = 10;
/* /*
* What program is execed by st depends of these precedence rules: * What program is execed by st depends of these precedence rules:
@ -181,6 +183,8 @@ static uint forcemousemod = ShiftMask;
*/ */
static MouseShortcut mshortcuts[] = { static MouseShortcut mshortcuts[] = {
/* mask button function argument release */ /* mask button function argument release */
{ XK_ANY_MOD, Button4, kscrollup, {.i = 1} },
{ XK_ANY_MOD, Button5, kscrolldown, {.i = 1} },
{ XK_ANY_MOD, Button2, selpaste, {.i = 0}, 1 }, { XK_ANY_MOD, Button2, selpaste, {.i = 0}, 1 },
{ ShiftMask, Button4, ttysend, {.s = "\033[5;2~"} }, { ShiftMask, Button4, ttysend, {.s = "\033[5;2~"} },
{ XK_ANY_MOD, Button4, ttysend, {.s = "\031"} }, { XK_ANY_MOD, Button4, ttysend, {.s = "\031"} },
@ -206,6 +210,8 @@ static Shortcut shortcuts[] = {
{ TERMMOD, XK_Y, selpaste, {.i = 0} }, { TERMMOD, XK_Y, selpaste, {.i = 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} },
}; };
/* /*

BIN
st

Binary file not shown.

385
st.c
View File

@ -42,6 +42,12 @@
#define ISCONTROLC1(c) (BETWEEN(c, 0x80, 0x9f)) #define ISCONTROLC1(c) (BETWEEN(c, 0x80, 0x9f))
#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 STRESCARGREST(n) ((n) == 0 ? strescseq.buf : strescseq.argp[(n)-1] + 1)
#define STRESCARGJUST(n) (*(strescseq.argp[n]) = '\0', STRESCARGREST(n))
#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,
@ -109,12 +115,20 @@ typedef struct {
int alt; int alt;
} Selection; } Selection;
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 */
@ -148,7 +162,7 @@ typedef struct {
char *buf; /* allocated raw string */ char *buf; /* allocated raw string */
size_t siz; /* allocation size */ size_t siz; /* allocation size */
size_t len; /* raw string length */ size_t len; /* raw string length */
char *args[STR_ARG_SIZ]; char *argp[STR_ARG_SIZ];
int narg; /* nb of args */ int narg; /* nb of args */
} STREscape; } STREscape;
@ -203,6 +217,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 +424,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 +538,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 +553,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 +581,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 +619,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;
@ -949,12 +966,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 +996,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;
} }
} }
@ -1000,23 +1023,18 @@ tcursor(int mode)
int alt = IS_SET(MODE_ALTSCREEN); 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 +1046,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 +1084,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 +1128,28 @@ tscrolldown(int orig, int n)
LIMIT(n, 0, term.bot-orig+1); LIMIT(n, 0, term.bot-orig+1);
tsetdirt(orig, term.bot-n); for (i = -n; i < 0; i++) {
tclearregion(0, term.bot-n+1, term.col-1, term.bot); 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;
} }
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 +1161,30 @@ 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);
} }
@ -1194,6 +1288,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.
@ -1202,25 +1297,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)
@ -1228,15 +1323,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;
@ -1244,6 +1340,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;
} }
} }
@ -1258,7 +1355,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);
@ -1275,7 +1372,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);
@ -1872,29 +1969,30 @@ strhandle(void)
}; };
term.esc &= ~(ESC_STR_END|ESC_STR); term.esc &= ~(ESC_STR_END|ESC_STR);
strparse(); strescseq.buf[strescseq.len] = '\0';
par = (narg = strescseq.narg) ? atoi(strescseq.args[0]) : 0;
switch (strescseq.type) { switch (strescseq.type) {
case ']': /* OSC -- Operating System Command */ case ']': /* OSC -- Operating System Command */
strparse();
par = (narg = strescseq.narg) ? atoi(STRESCARGJUST(0)) : 0;
switch (par) { switch (par) {
case 0: case 0:
if (narg > 1) { if (narg > 1) {
xsettitle(strescseq.args[1]); xsettitle(STRESCARGREST(1));
xseticontitle(strescseq.args[1]); xseticontitle(STRESCARGREST(1));
} }
return; return;
case 1: case 1:
if (narg > 1) if (narg > 1)
xseticontitle(strescseq.args[1]); xseticontitle(STRESCARGREST(1));
return; return;
case 2: case 2:
if (narg > 1) if (narg > 1)
xsettitle(strescseq.args[1]); xsettitle(STRESCARGREST(1));
return; return;
case 52: case 52:
if (narg > 2 && allowwindowops) { if (narg > 2 && allowwindowops) {
dec = base64dec(strescseq.args[2]); dec = base64dec(STRESCARGREST(2));
if (dec) { if (dec) {
xsetsel(dec); xsetsel(dec);
xclipcopy(); xclipcopy();
@ -1908,7 +2006,7 @@ strhandle(void)
case 12: case 12:
if (narg < 2) if (narg < 2)
break; break;
p = strescseq.args[1]; p = STRESCARGREST(1);
if ((j = par - 10) < 0 || j >= LEN(osc_table)) if ((j = par - 10) < 0 || j >= LEN(osc_table))
break; /* shouldn't be possible */ break; /* shouldn't be possible */
@ -1924,10 +2022,10 @@ strhandle(void)
case 4: /* color set */ case 4: /* color set */
if (narg < 3) if (narg < 3)
break; break;
p = strescseq.args[2]; p = STRESCARGJUST(2);
/* FALLTHROUGH */ /* FALLTHROUGH */
case 104: /* color reset */ case 104: /* color reset */
j = (narg > 1) ? atoi(strescseq.args[1]) : -1; j = (narg > 1) ? atoi(STRESCARGJUST(1)) : -1;
if (p && !strcmp(p, "?")) { if (p && !strcmp(p, "?")) {
osc_color_response(j, 0, 1); osc_color_response(j, 0, 1);
@ -1947,7 +2045,7 @@ strhandle(void)
} }
break; break;
case 'k': /* old title set compatibility */ case 'k': /* old title set compatibility */
xsettitle(strescseq.args[0]); xsettitle(strescseq.buf);
return; return;
case 'P': /* DCS -- Device Control String */ case 'P': /* DCS -- Device Control String */
case '_': /* APC -- Application Program Command */ case '_': /* APC -- Application Program Command */
@ -1966,18 +2064,17 @@ strparse(void)
char *p = strescseq.buf; char *p = strescseq.buf;
strescseq.narg = 0; strescseq.narg = 0;
strescseq.buf[strescseq.len] = '\0';
if (*p == '\0') if (*p == '\0')
return; return;
while (strescseq.narg < STR_ARG_SIZ) { while (strescseq.narg < STR_ARG_SIZ) {
strescseq.args[strescseq.narg++] = p;
while ((c = *p) != ';' && c != '\0') while ((c = *p) != ';' && c != '\0')
++p; p++;
strescseq.argp[strescseq.narg++] = p;
if (c == '\0') if (c == '\0')
return; return;
*p++ = '\0'; p++;
} }
} }
@ -2069,7 +2166,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)
@ -2452,11 +2549,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)
@ -2464,7 +2561,7 @@ check_control_code:
if (term.c.x+width > term.col) { if (term.c.x+width > term.col) {
tnewline(1); tnewline(1);
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);
@ -2495,6 +2592,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 */
@ -2521,15 +2623,35 @@ 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;
@ -2540,37 +2662,52 @@ tresize(int col, int row)
* tscrollup would work here, but we can optimize to * tscrollup would work here, but we can optimize to
* memmove because we're freeing the earlier lines * memmove because we're freeing the earlier lines
*/ */
for (i = 0; i <= term.c.y - row; i++) { /* Shift buffer to keep the cursor where we expect it */
free(term.line[i]); if (row <= term.c.y) {
free(term.alt[i]); 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 */ /* ensure that both src and dst are not NULL */
if (i > 0) { /* Allocate all visible lines for regular line buffer */
memmove(term.line, term.line + i, row * sizeof(Line)); for (j = term.screen[0].cur, i = 0; i < row; ++i, j = (j + 1) % term.screen[0].size)
memmove(term.alt, term.alt + i, row * sizeof(Line)); {
if (!term.screen[0].buffer[j]) {
term.screen[0].buffer[j] = xmalloc(linelen * sizeof(Glyph));
} }
for (i += row; i < term.row; i++) { if (i >= term.row) {
free(term.line[i]); clearline(term.screen[0].buffer[j], term.c.attr, 0, linelen);
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 */ /* 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;
@ -2580,26 +2717,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
@ -2611,14 +2738,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; 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 +2761,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();

1
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 10000
enum glyph_attribute { enum glyph_attribute {
ATTR_NULL = 0, ATTR_NULL = 0,

BIN
st.o

Binary file not shown.

2
x.c
View File

@ -59,6 +59,8 @@ 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"

BIN
x.o

Binary file not shown.