From bd6f16f5e52d51de7fb633a91b84e685aa885025 Mon Sep 17 00:00:00 2001 From: Aiden Gall Date: Thu, 16 Nov 2023 02:10:50 +0000 Subject: patch scrollback-reflow --- config.def.h | 2 + st.c | 916 +++++++++++++++++++++++++++++++++++++++++++---------------- st.h | 27 +- 3 files changed, 685 insertions(+), 260 deletions(-) diff --git a/config.def.h b/config.def.h index 91ab8ca..e3b469b 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 51049ba..230ef3a 100644 --- a/st.c +++ b/st.c @@ -35,6 +35,8 @@ #define ESC_ARG_SIZ 16 #define STR_BUF_SIZ ESC_BUF_SIZ #define STR_ARG_SIZ ESC_ARG_SIZ +#define HISTSIZE 2000 +#define RESIZEBUFFER 1000 /* macros */ #define IS_SET(flag) ((term.mode & (flag)) != 0) @@ -43,6 +45,22 @@ #define ISCONTROL(c) (ISCONTROLC0(c) || ISCONTROLC1(c)) #define ISDELIM(u) (u && wcschr(worddelimiters, u)) +#define TLINE(y) ( \ + (y) < term.scr ? term.hist[(term.histi + (y) - term.scr + 1 + HISTSIZE) % HISTSIZE] \ + : term.line[(y) - term.scr] \ +) + +#define TLINEABS(y) ( \ + (y) < 0 ? term.hist[(term.histi + (y) + 1 + HISTSIZE) % HISTSIZE] : term.line[(y)] \ +) + +#define UPDATEWRAPNEXT(alt, col) do { \ + if ((term.c.state & CURSOR_WRAPNEXT) && term.c.x + term.wrapcwidth[alt] < col) { \ + term.c.x += term.wrapcwidth[alt]; \ + term.c.state &= ~CURSOR_WRAPNEXT; \ + } \ +} while (0); + enum term_mode { MODE_WRAP = 1 << 0, MODE_INSERT = 1 << 1, @@ -53,6 +71,12 @@ enum term_mode { MODE_UTF8 = 1 << 6, }; +enum scroll_mode { + SCROLL_RESIZE = -1, + SCROLL_NOSAVEHIST = 0, + SCROLL_SAVEHIST = 1 +}; + enum cursor_movement { CURSOR_SAVE, CURSOR_LOAD @@ -114,7 +138,11 @@ typedef struct { int row; /* nb row */ int col; /* nb col */ Line *line; /* screen */ - Line *alt; /* alternate screen */ + Line hist[HISTSIZE]; /* history buffer */ + int histi; /* history index */ + int histf; /* nb history available */ + int scr; /* scroll back */ + int wrapcwidth[2]; /* used in updating WRAPNEXT when resizing */ int *dirty; /* dirtyness of lines */ TCursor c; /* cursor */ int ocx; /* old cursor col */ @@ -171,26 +199,37 @@ static void tprinter(char *, size_t); static void tdumpsel(void); static void tdumpline(int); static void tdump(void); -static void tclearregion(int, int, int, int); +static void tclearregion(int, int, int, int, int); static void tcursor(int); +static void tclearglyph(Glyph *, int); +static void tresetcursor(void); static void tdeletechar(int); static void tdeleteline(int); static void tinsertblank(int); static void tinsertblankline(int); -static int tlinelen(int); +static int tlinelen(Line len); +static int tiswrapped(Line line); +static char *tgetglyphs(char *, const Glyph *, const Glyph *); +static size_t tgetline(char *, const Glyph *); static void tmoveto(int, int); static void tmoveato(int, int); static void tnewline(int); static void tputtab(int); static void tputc(Rune); static void treset(void); -static void tscrollup(int, int); +static void tscrollup(int, int, int, int); static void tscrolldown(int, int); +static void treflow(int, int); +static void rscrolldown(int); +static void tresizedef(int, int); +static void tresizealt(int, int); static void tsetattr(const int *, int); static void tsetchar(Rune, const Glyph *, int, int); static void tsetdirt(int, int); static void tsetscroll(int, int); static void tswapscreen(void); +static void tloaddefscreen(int, int); +static void tloadaltscreen(int, int); static void tsetmode(int, int, const int *, int); static int twrite(const char *, int, int); static void tfulldirt(void); @@ -204,7 +243,10 @@ static void tstrsequence(uchar); static void drawregion(int, int, int, int); static void selnormalize(void); -static void selscroll(int, int); +static void selscroll(int, int, int); +static void selmove(int); +static void selremove(void); +static int regionselected(int, int, int, int); static void selsnap(int *, int *, int); static size_t utf8decode(const char *, Rune *, size_t); @@ -412,17 +454,46 @@ selinit(void) } int -tlinelen(int y) +tlinelen(Line line) { - int i = term.col; + int i = term.col - 1; + + for (; i >= 0 && !(line[i].mode & (ATTR_SET | ATTR_WRAP)); i--); + return i + 1; +} - if (term.line[y][i - 1].mode & ATTR_WRAP) - return i; +int +tiswrapped(Line line) +{ + int len = tlinelen(line); - while (i > 0 && term.line[y][i - 1].u == ' ') - --i; + return len > 0 && (line[len - 1].mode & ATTR_WRAP); +} - return i; +char * +tgetglyphs(char *buf, const Glyph *gp, const Glyph *lgp) +{ + while (gp <= lgp) + if (gp->mode & ATTR_WDUMMY) { + gp++; + } else { + buf += utf8encode((gp++)->u, buf); + } + return buf; +} + +size_t +tgetline(char *buf, const Glyph *fgp) +{ + char *ptr; + const Glyph *lgp = &fgp[term.col - 1]; + + while (lgp > fgp && !(lgp->mode & (ATTR_SET | ATTR_WRAP))) + lgp--; + ptr = tgetglyphs(buf, fgp, lgp); + if (!(lgp->mode & ATTR_WRAP)) + *(ptr++) = '\n'; + return ptr - buf; } void @@ -462,10 +533,11 @@ selextend(int col, int row, int type, int done) sel.oe.x = col; sel.oe.y = row; - selnormalize(); sel.type = type; + selnormalize(); - if (oldey != sel.oe.y || oldex != sel.oe.x || oldtype != sel.type || sel.mode == SEL_EMPTY) + if (oldey != sel.oe.y || oldex != sel.oe.x || + oldtype != sel.type || sel.mode == SEL_EMPTY) tsetdirt(MIN(sel.nb.y, oldsby), MAX(sel.ne.y, oldsey)); sel.mode = done ? SEL_IDLE : SEL_READY; @@ -492,43 +564,50 @@ selnormalize(void) /* expand selection over line breaks */ if (sel.type == SEL_RECTANGULAR) return; - i = tlinelen(sel.nb.y); - if (i < sel.nb.x) + + i = tlinelen(TLINE(sel.nb.y)); + if (sel.nb.x > i) sel.nb.x = i; - if (tlinelen(sel.ne.y) <= sel.ne.x) - sel.ne.x = term.col - 1; + if (sel.ne.x >= tlinelen(TLINE(sel.ne.y))) + sel.ne.x = term.col - 1; } int -selected(int x, int y) +regionselected(int x1, int y1, int x2, int y2) { - if (sel.mode == SEL_EMPTY || sel.ob.x == -1 || - sel.alt != IS_SET(MODE_ALTSCREEN)) + if (sel.ob.x == -1 || sel.mode == SEL_EMPTY || + sel.alt != IS_SET(MODE_ALTSCREEN) || sel.nb.y > y2 || sel.ne.y < y1) return 0; - if (sel.type == SEL_RECTANGULAR) - return BETWEEN(y, sel.nb.y, sel.ne.y) - && BETWEEN(x, sel.nb.x, sel.ne.x); + return (sel.type == SEL_RECTANGULAR) ? sel.nb.x <= x2 && sel.ne.x >= x1 + : (sel.nb.y != y2 || sel.nb.x <= x2) && + (sel.ne.y != y1 || sel.ne.x >= x1); +} - return BETWEEN(y, sel.nb.y, sel.ne.y) - && (y != sel.nb.y || x >= sel.nb.x) - && (y != sel.ne.y || x <= sel.ne.x); +int +selected(int x, int y) +{ + return regionselected(x, y, x, y); } void selsnap(int *x, int *y, int direction) { int newx, newy, xt, yt; + int rtop = 0, rbot = term.row - 1; int delim, prevdelim; const Glyph *gp, *prevgp; + if (!IS_SET(MODE_ALTSCREEN)) + rtop += -term.histf + term.scr, rbot += term.scr; + switch (sel.snap) { case SNAP_WORD: /* * 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,24 +615,24 @@ selsnap(int *x, int *y, int direction) if (!BETWEEN(newx, 0, term.col - 1)) { newy += direction; newx = (newx + term.col) % term.col; - if (!BETWEEN(newy, 0, term.row - 1)) + if (!BETWEEN(newy, rtop, rbot)) break; if (direction > 0) 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)) + if (newx >= tlinelen(TLINE(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))) + if (!(gp->mode & ATTR_WDUMMY) && (delim != prevdelim || + (delim && !(gp->u == ' ' && prevgp->u == ' ')))) break; *x = newx; @@ -570,18 +649,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 - & ATTR_WRAP)) { + for (; *y > rtop; *y -= 1) { + if (!tiswrapped(TLINE(*y-1))) break; - } } } else if (direction > 0) { - for (; *y < term.row-1; *y += direction) { - if (!(term.line[*y][term.col-1].mode - & ATTR_WRAP)) { + for (; *y < rbot; *y += 1) { + if (!tiswrapped(TLINE(*y))) break; - } } } break; @@ -592,40 +667,34 @@ char * getsel(void) { char *str, *ptr; - int y, bufsize, lastx, linelen; - const Glyph *gp, *last; + int y, lastx, linelen; + const Glyph *gp, *lgp; - if (sel.ob.x == -1) + if (sel.ob.x == -1 || sel.alt != IS_SET(MODE_ALTSCREEN)) return NULL; - bufsize = (term.col+1) * (sel.ne.y-sel.nb.y+1) * UTF_SIZ; - ptr = str = xmalloc(bufsize); + str = xmalloc((term.col + 1) * (sel.ne.y - sel.nb.y + 1) * UTF_SIZ); + ptr = str; /* append every set & selected glyph to the selection */ for (y = sel.nb.y; y <= sel.ne.y; y++) { - if ((linelen = tlinelen(y)) == 0) { + Line line = TLINE(y); + + if ((linelen = tlinelen(line)) == 0) { *ptr++ = '\n'; continue; } if (sel.type == SEL_RECTANGULAR) { - gp = &term.line[y][sel.nb.x]; + gp = &line[sel.nb.x]; lastx = sel.ne.x; } else { - gp = &term.line[y][sel.nb.y == y ? sel.nb.x : 0]; + gp = &line[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)]; - while (last >= gp && last->u == ' ') - --last; - - for ( ; gp <= last; ++gp) { - if (gp->mode & ATTR_WDUMMY) - continue; - - ptr += utf8encode(gp->u, ptr); - } + lgp = &line[MIN(lastx, linelen-1)]; + ptr = tgetglyphs(ptr, gp, lgp); /* * Copy and pasting of line endings is inconsistent * in the inconsistent terminal and GUI world. @@ -636,10 +705,10 @@ getsel(void) * FIXME: Fix the computer world. */ if ((y < sel.ne.y || lastx >= linelen) && - (!(last->mode & ATTR_WRAP) || sel.type == SEL_RECTANGULAR)) + (!(lgp->mode & ATTR_WRAP) || sel.type == SEL_RECTANGULAR)) *ptr++ = '\n'; } - *ptr = 0; + *ptr = '\0'; return str; } @@ -648,9 +717,15 @@ selclear(void) { if (sel.ob.x == -1) return; + selremove(); + tsetdirt(sel.nb.y, sel.ne.y); +} + +void +selremove(void) +{ sel.mode = SEL_IDLE; sel.ob.x = -1; - tsetdirt(sel.nb.y, sel.ne.y); } void @@ -852,6 +927,7 @@ ttywrite(const char *s, size_t n, int may_echo) { const char *next; + kscrolldown(&((Arg){ .i = term.scr })); if (may_echo && IS_SET(MODE_ECHO)) twrite(s, n, 1); @@ -987,7 +1063,7 @@ tsetdirtattr(int attr) for (i = 0; i < term.row-1; i++) { for (j = 0; j < term.col-1; j++) { if (term.line[i][j].mode & attr) { - tsetdirt(i, i); + term.dirty[i] = 1; break; } } @@ -997,7 +1073,8 @@ tsetdirtattr(int attr) void tfulldirt(void) { - tsetdirt(0, term.row-1); + for (int i = 0; i < term.row; i++) + term.dirty[i] = 1; } void @@ -1014,110 +1091,258 @@ tcursor(int mode) } } +void +tresetcursor(void) +{ + term.c = (TCursor){ { .mode = ATTR_NULL, .fg = defaultfg, .bg = defaultbg }, + .x = 0, .y = 0, .state = CURSOR_DEFAULT }; +} + void treset(void) { uint i; + int x, y; - term.c = (TCursor){{ - .mode = ATTR_NULL, - .fg = defaultfg, - .bg = defaultbg - }, .x = 0, .y = 0, .state = CURSOR_DEFAULT}; + tresetcursor(); memset(term.tabs, 0, term.col * sizeof(*term.tabs)); for (i = tabspaces; i < term.col; i += tabspaces) term.tabs[i] = 1; term.top = 0; + term.histf = 0; + term.scr = 0; term.bot = term.row - 1; term.mode = MODE_WRAP|MODE_UTF8; memset(term.trantbl, CS_USA, sizeof(term.trantbl)); term.charset = 0; + selremove(); for (i = 0; i < 2; i++) { - tmoveto(0, 0); - tcursor(CURSOR_SAVE); - tclearregion(0, 0, term.col-1, term.row-1); + tcursor(CURSOR_SAVE); /* reset saved cursor */ + for (y = 0; y < term.row; y++) + for (x = 0; x < term.col; x++) + tclearglyph(&term.line[y][x], 0); tswapscreen(); } + tfulldirt(); } void tnew(int col, int row) { - term = (Term){ .c = { .attr = { .fg = defaultfg, .bg = defaultbg } } }; - tresize(col, row); - treset(); + int i, j; + + for (i = 0; i < 2; i++) { + term.line = xmalloc(row * sizeof(Line)); + for (j = 0; j < row; j++) + term.line[j] = xmalloc(col * sizeof(Glyph)); + term.col = col, term.row = row; + tswapscreen(); + } + term.dirty = xmalloc(row * sizeof(*term.dirty)); + term.tabs = xmalloc(col * sizeof(*term.tabs)); + for (i = 0; i < HISTSIZE; i++) + term.hist[i] = xmalloc(col * sizeof(Glyph)); + treset(); } +/* handle it with care */ void tswapscreen(void) { - Line *tmp = term.line; + static Line *altline; + static int altcol, altrow; + Line *tmpline = term.line; + int tmpcol = term.col, tmprow = term.row; - term.line = term.alt; - term.alt = tmp; + term.line = altline; + term.col = altcol, term.row = altrow; + altline = tmpline; + altcol = tmpcol, altrow = tmprow; term.mode ^= MODE_ALTSCREEN; +} + +void +tloaddefscreen(int clear, int loadcursor) +{ + int col, row, alt = IS_SET(MODE_ALTSCREEN); + + if (alt) { + if (clear) + tclearregion(0, 0, term.col-1, term.row-1, 1); + col = term.col, row = term.row; + tswapscreen(); + } + if (loadcursor) + tcursor(CURSOR_LOAD); + if (alt) + tresizedef(col, row); +} + +void +tloadaltscreen(int clear, int savecursor) +{ + int col, row, def = !IS_SET(MODE_ALTSCREEN); + + if (savecursor) + tcursor(CURSOR_SAVE); + if (def) { + col = term.col, row = term.row; + tswapscreen(); + term.scr = 0; + tresizealt(col, row); + } + if (clear) + tclearregion(0, 0, term.col-1, term.row-1, 1); +} + +int +tisaltscreen(void) +{ + return IS_SET(MODE_ALTSCREEN); +} + +void +kscrolldown(const Arg* a) +{ + int n = a->i; + + if (!term.scr || IS_SET(MODE_ALTSCREEN)) + return; + + if (n < 0) + n = MAX(term.row / -n, 1); + + if (n <= term.scr) { + term.scr -= n; + } else { + n = term.scr; + term.scr = 0; + } + + if (sel.ob.x != -1 && !sel.alt) + selmove(-n); /* negate change in term.scr */ tfulldirt(); } void -tscrolldown(int orig, int n) +kscrollup(const Arg* a) { - int i; + int n = a->i; + + if (!term.histf || IS_SET(MODE_ALTSCREEN)) + return; + + if (n < 0) + n = MAX(term.row / -n, 1); + + if (term.scr + n <= term.histf) { + term.scr += n; + } else { + n = term.histf - term.scr; + term.scr = term.histf; + } + + if (sel.ob.x != -1 && !sel.alt) + selmove(n); /* negate change in term.scr */ + tfulldirt(); +} + +void +tscrolldown(int top, int n) +{ + int i, bot = term.bot; Line temp; - LIMIT(n, 0, term.bot-orig+1); + if (n <= 0) + return; + n = MIN(n, bot-top+1); - tsetdirt(orig, term.bot-n); - tclearregion(0, term.bot-n+1, term.col-1, term.bot); + tsetdirt(top, bot-n); + tclearregion(0, bot-n+1, term.col-1, bot, 1); - for (i = term.bot; i >= orig+n; i--) { + for (i = bot; i >= top+n; i--) { temp = term.line[i]; term.line[i] = term.line[i-n]; term.line[i-n] = temp; } - selscroll(orig, n); + if (sel.ob.x != -1 && sel.alt == IS_SET(MODE_ALTSCREEN)) + selscroll(top, bot, n); } void -tscrollup(int orig, int n) +tscrollup(int top, int bot, int n, int mode) { - int i; + int i, j, s; + int alt = IS_SET(MODE_ALTSCREEN); + int savehist = !alt && top == 0 && mode != SCROLL_NOSAVEHIST; Line temp; - LIMIT(n, 0, term.bot-orig+1); - - tclearregion(0, orig, term.col-1, orig+n-1); - tsetdirt(orig+n, term.bot); + if (n <= 0) + return; + n = MIN(n, bot-top+1); + + if (savehist) { + for (i = 0; i < n; i++) { + term.histi = (term.histi + 1) % HISTSIZE; + temp = term.hist[term.histi]; + for (j = 0; j < term.col; j++) + tclearglyph(&temp[j], 1); + term.hist[term.histi] = term.line[i]; + term.line[i] = temp; + } + term.histf = MIN(term.histf + n, HISTSIZE); + s = n; + if (term.scr) { + j = term.scr; + term.scr = MIN(j + n, HISTSIZE); + s = j + n - term.scr; + } + if (mode != SCROLL_RESIZE) + tfulldirt(); + } else { + tclearregion(0, top, term.col-1, top+n-1, 1); + tsetdirt(top+n, bot); + } - for (i = orig; i <= term.bot-n; i++) { + for (i = top; i <= bot-n; i++) { temp = term.line[i]; term.line[i] = term.line[i+n]; term.line[i+n] = temp; } - selscroll(orig, -n); + if (sel.ob.x != -1 && sel.alt == alt) { + if (!savehist) { + selscroll(top, bot, -n); + } else if (s > 0) { + selmove(-s); + if (-term.scr + sel.nb.y < -term.histf) + selremove(); + } + } } void -selscroll(int orig, int n) +selmove(int n) { - if (sel.ob.x == -1) - return; + sel.ob.y += n, sel.nb.y += n; + sel.oe.y += n, sel.ne.y += n; +} - if (BETWEEN(sel.nb.y, orig, term.bot) != BETWEEN(sel.ne.y, orig, term.bot)) { +void +selscroll(int top, int bot, int n) +{ + /* turn absolute coordinates into relative */ + top += term.scr, bot += term.scr; + + if (BETWEEN(sel.nb.y, top, bot) != BETWEEN(sel.ne.y, top, bot)) { selclear(); - } else if (BETWEEN(sel.nb.y, orig, term.bot)) { - sel.ob.y += n; - sel.oe.y += n; - if (sel.ob.y < term.top || sel.ob.y > term.bot || - sel.oe.y < term.top || sel.oe.y > term.bot) { + } else if (BETWEEN(sel.nb.y, top, bot)) { + selmove(n); + if (sel.nb.y < top || sel.ne.y > bot) selclear(); - } else { - selnormalize(); - } } } @@ -1127,7 +1352,7 @@ tnewline(int first_col) int y = term.c.y; if (y == term.bot) { - tscrollup(term.top, 1); + tscrollup(term.top, term.bot, 1, SCROLL_SAVEHIST); } else { y++; } @@ -1217,75 +1442,79 @@ tsetchar(Rune u, const Glyph *attr, int x, int y) } else if (term.line[y][x].mode & ATTR_WDUMMY) { term.line[y][x-1].u = ' '; term.line[y][x-1].mode &= ~ATTR_WIDE; - } + } term.dirty[y] = 1; term.line[y][x] = *attr; term.line[y][x].u = u; + term.line[y][x].mode |= ATTR_SET; } void -tclearregion(int x1, int y1, int x2, int y2) +tclearglyph(Glyph *gp, int usecurattr) { - int x, y, temp; - Glyph *gp; + if (usecurattr) { + gp->fg = term.c.attr.fg; + gp->bg = term.c.attr.bg; + } else { + gp->fg = defaultfg; + gp->bg = defaultbg; + } + gp->mode = ATTR_NULL; + gp->u = ' '; +} - if (x1 > x2) - temp = x1, x1 = x2, x2 = temp; - if (y1 > y2) - temp = y1, y1 = y2, y2 = temp; +void +tclearregion(int x1, int y1, int x2, int y2, int usecurattr) +{ + int x, y; - LIMIT(x1, 0, term.col-1); - LIMIT(x2, 0, term.col-1); - LIMIT(y1, 0, term.row-1); - LIMIT(y2, 0, term.row-1); + /* regionselected() takes relative coordinates */ + if (regionselected(x1+term.scr, y1+term.scr, x2+term.scr, y2+term.scr)) + selremove(); for (y = y1; y <= y2; y++) { term.dirty[y] = 1; - for (x = x1; x <= x2; x++) { - gp = &term.line[y][x]; - if (selected(x, y)) - selclear(); - gp->fg = term.c.attr.fg; - gp->bg = term.c.attr.bg; - gp->mode = 0; - gp->u = ' '; - } + for (x = x1; x <= x2; x++) + tclearglyph(&term.line[y][x], usecurattr); } } void tdeletechar(int n) { - int dst, src, size; - Glyph *line; - - LIMIT(n, 0, term.col - term.c.x); + int src, dst, size; + Line line; + if (n <= 0) + return; dst = term.c.x; - src = term.c.x + n; + src = MIN(term.c.x + n, term.col); size = term.col - src; - line = term.line[term.c.y]; - - memmove(&line[dst], &line[src], size * sizeof(Glyph)); - tclearregion(term.col-n, term.c.y, term.col-1, term.c.y); + if (size > 0) { /* otherwise src would point beyond the array + https://stackoverflow.com/questions/29844298 */ + line = term.line[term.c.y]; + memmove(&line[dst], &line[src], size * sizeof(Glyph)); + } + tclearregion(dst + size, term.c.y, term.col - 1, term.c.y, 1); } void tinsertblank(int n) { - int dst, src, size; - Glyph *line; - - LIMIT(n, 0, term.col - term.c.x); + int src, dst, size; + Line line; - dst = term.c.x + n; + if (n <= 0) + return; + dst = MIN(term.c.x + n, term.col); src = term.c.x; size = term.col - dst; - line = term.line[term.c.y]; - - memmove(&line[dst], &line[src], size * sizeof(Glyph)); - tclearregion(src, term.c.y, dst - 1, term.c.y); + if (size > 0) { /* otherwise dst would point beyond the array */ + line = term.line[term.c.y]; + memmove(&line[dst], &line[src], size * sizeof(Glyph)); + } + tclearregion(src, term.c.y, dst - 1, term.c.y, 1); } void @@ -1299,7 +1528,7 @@ void tdeleteline(int n) { if (BETWEEN(term.c.y, term.top, term.bot)) - tscrollup(term.c.y, n); + tscrollup(term.c.y, term.bot, n, SCROLL_NOSAVEHIST); } int32_t @@ -1473,7 +1702,7 @@ tsetscroll(int t, int b) void tsetmode(int priv, int set, const int *args, int narg) { - int alt; const int *lim; + const int *lim; for (lim = args + narg; args < lim; ++args) { if (priv) { @@ -1534,25 +1763,18 @@ tsetmode(int priv, int set, const int *args, int narg) xsetmode(set, MODE_8BIT); break; case 1049: /* swap screen & set/restore cursor as xterm */ - if (!allowaltscreen) - break; - tcursor((set) ? CURSOR_SAVE : CURSOR_LOAD); - /* FALLTHROUGH */ case 47: /* swap screen */ - case 1047: + case 1047: /* swap screen, clearing alternate screen */ if (!allowaltscreen) break; - alt = IS_SET(MODE_ALTSCREEN); - if (alt) { - tclearregion(0, 0, term.col-1, - term.row-1); - } - if (set ^ alt) /* set is always 1 or 0 */ - tswapscreen(); - if (*args != 1049) - break; - /* FALLTHROUGH */ + if (set) + tloadaltscreen(*args == 1049, *args == 1049); + else + tloaddefscreen(*args == 1047, *args == 1049); + break; case 1048: + if (!allowaltscreen) + break; tcursor((set) ? CURSOR_SAVE : CURSOR_LOAD); break; case 2004: /* 2004: bracketed paste mode */ @@ -1604,7 +1826,7 @@ void csihandle(void) { char buf[40]; - int len; + int n, x; switch (csiescseq.mode[0]) { default: @@ -1702,20 +1924,30 @@ csihandle(void) case 'J': /* ED -- Clear screen */ switch (csiescseq.arg[0]) { case 0: /* below */ - tclearregion(term.c.x, term.c.y, term.col-1, term.c.y); + tclearregion(term.c.x, term.c.y, term.col-1, term.c.y, 1); if (term.c.y < term.row-1) { - tclearregion(0, term.c.y+1, term.col-1, - term.row-1); + tclearregion(0, term.c.y+1, term.col-1, term.row-1, 1); } break; case 1: /* above */ - if (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); + if (term.c.y >= 1) + tclearregion(0, 0, term.col-1, term.c.y-1, 1); + tclearregion(0, term.c.y, term.c.x, term.c.y, 1); break; case 2: /* all */ - tclearregion(0, 0, term.col-1, term.row-1); + if (IS_SET(MODE_ALTSCREEN)) { + tclearregion(0, 0, term.col-1, term.row-1, 1); break; + } + /* vte does this: + tscrollup(0, term.row-1, term.row, SCROLL_SAVEHIST); */ + + /* alacritty does this: */ + for (n = term.row-1; n >= 0 && tlinelen(term.line[n]) == 0; n--); + if (n >= 0) + tscrollup(0, term.row-1, n+1, SCROLL_SAVEHIST); + tscrollup(0, term.row-1, term.row-n-1, SCROLL_NOSAVEHIST); + break; default: goto unknown; } @@ -1723,20 +1955,20 @@ csihandle(void) case 'K': /* EL -- Clear line */ switch (csiescseq.arg[0]) { case 0: /* right */ - tclearregion(term.c.x, term.c.y, term.col-1, - term.c.y); + tclearregion(term.c.x, term.c.y, term.col-1, term.c.y, 1); break; case 1: /* left */ - tclearregion(0, term.c.y, term.c.x, term.c.y); + tclearregion(0, term.c.y, term.c.x, term.c.y, 1); break; case 2: /* all */ - tclearregion(0, term.c.y, term.col-1, term.c.y); + tclearregion(0, term.c.y, term.col-1, term.c.y, 1); break; } break; case 'S': /* SU -- Scroll line up */ DEFAULT(csiescseq.arg[0], 1); - tscrollup(term.top, csiescseq.arg[0]); + /* xterm, urxvt, alacritty save this in history */ + tscrollup(term.top, term.bot, csiescseq.arg[0], SCROLL_SAVEHIST); break; case 'T': /* SD -- Scroll line down */ DEFAULT(csiescseq.arg[0], 1); @@ -1754,9 +1986,11 @@ csihandle(void) tdeleteline(csiescseq.arg[0]); break; case 'X': /* ECH -- Erase char */ + if (csiescseq.arg[0] < 0) + return; DEFAULT(csiescseq.arg[0], 1); - tclearregion(term.c.x, term.c.y, - term.c.x + csiescseq.arg[0] - 1, term.c.y); + x = MIN(term.c.x + csiescseq.arg[0], term.col) - 1; + tclearregion(term.c.x, term.c.y, x, term.c.y, 1); break; case 'P': /* DCH -- Delete char */ DEFAULT(csiescseq.arg[0], 1); @@ -1778,9 +2012,9 @@ csihandle(void) break; case 'n': /* DSR – Device Status Report (cursor position) */ if (csiescseq.arg[0] == 6) { - len = snprintf(buf, sizeof(buf), "\033[%i;%iR", + n = snprintf(buf, sizeof(buf), "\033[%i;%iR", term.c.y+1, term.c.x+1); - ttywrite(buf, len, 0); + ttywrite(buf, n, 0); } break; case 'r': /* DECSTBM -- Set Scrolling Region */ @@ -2100,16 +2334,8 @@ tdumpsel(void) void tdumpline(int n) { - char buf[UTF_SIZ]; - const Glyph *bp, *end; - - bp = &term.line[n][0]; - end = &bp[MIN(tlinelen(n), term.col) - 1]; - if (bp != end || bp->u != ' ') { - for ( ; bp <= end; ++bp) - tprinter(buf, utf8encode(bp->u, buf)); - } - tprinter("\n", 1); + char str[(term.col + 1) * UTF_SIZ]; + tprinter(str, tgetline(str, &term.line[n][0])); } void @@ -2330,7 +2556,7 @@ eschandle(uchar ascii) return 0; case 'D': /* IND -- Linefeed */ if (term.c.y == term.bot) { - tscrollup(term.top, 1); + tscrollup(term.top, term.bot, 1, SCROLL_SAVEHIST); } else { tmoveto(term.c.x, term.c.y+1); } @@ -2483,7 +2709,8 @@ check_control_code: */ return; } - if (selected(term.c.x, term.c.y)) + /* selected() takes relative coordinates */ + if (selected(term.c.x + term.scr, term.c.y + term.scr)) selclear(); gp = &term.line[term.c.y][term.c.x]; @@ -2518,6 +2745,7 @@ check_control_code: if (term.c.x+width < term.col) { tmoveto(term.c.x+width, term.c.y); } else { + term.wrapcwidth[IS_SET(MODE_ALTSCREEN)] = width; term.c.state |= CURSOR_WRAPNEXT; } } @@ -2555,85 +2783,275 @@ twrite(const char *buf, int buflen, int show_ctrl) } void -tresize(int col, int row) +treflow(int col, int row) { - int i; - int minrow = MIN(row, term.row); - int mincol = MIN(col, term.col); - int *bp; - TCursor c; - - if (col < 1 || row < 1) { - fprintf(stderr, - "tresize: error resizing to %dx%d\n", col, row); - return; + int i, j; + int oce, nce, bot, scr; + int ox = 0, oy = -term.histf, nx = 0, ny = -1, len; + int cy = -1; /* proxy for new y coordinate of cursor */ + int nlines; + Line *buf, line; + + /* y coordinate of cursor line end */ + for (oce = term.c.y; oce < term.row - 1 && + tiswrapped(term.line[oce]); oce++); + + nlines = term.histf + oce + 1; + if (col < term.col) { + /* each line can take this many lines after reflow */ + j = (term.col + col - 1) / col; + nlines = j * nlines; + if (nlines > HISTSIZE + RESIZEBUFFER + row) { + nlines = HISTSIZE + RESIZEBUFFER + row; + oy = -(nlines / j - oce - 1); + } } + buf = xmalloc(nlines * sizeof(Line)); + do { + if (!nx) + buf[++ny] = xmalloc(col * sizeof(Glyph)); + if (!ox) { + line = TLINEABS(oy); + len = tlinelen(line); + } + if (oy == term.c.y) { + if (!ox) + len = MAX(len, term.c.x + 1); + /* update cursor */ + if (cy < 0 && term.c.x - ox < col - nx) { + term.c.x = nx + term.c.x - ox, cy = ny; + UPDATEWRAPNEXT(0, col); + } + } + /* get reflowed lines in buf */ + if (col - nx > len - ox) { + memcpy(&buf[ny][nx], &line[ox], (len-ox) * sizeof(Glyph)); + nx += len - ox; + if (len == 0 || !(line[len - 1].mode & ATTR_WRAP)) { + for (j = nx; j < col; j++) + tclearglyph(&buf[ny][j], 0); + nx = 0; + } else if (nx > 0) { + buf[ny][nx - 1].mode &= ~ATTR_WRAP; + } + ox = 0, oy++; + } else if (col - nx == len - ox) { + memcpy(&buf[ny][nx], &line[ox], (col-nx) * sizeof(Glyph)); + ox = 0, oy++, nx = 0; + } else/* if (col - nx < len - ox) */ { + memcpy(&buf[ny][nx], &line[ox], (col-nx) * sizeof(Glyph)); + ox += col - nx; + buf[ny][col - 1].mode |= ATTR_WRAP; + nx = 0; + } + } while (oy <= oce); + if (nx) + for (j = nx; j < col; j++) + tclearglyph(&buf[ny][j], 0); - /* - * 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 extra lines */ + for (i = row; i < term.row; i++) free(term.line[i]); - free(term.alt[i]); + /* resize to new height */ + term.line = xrealloc(term.line, row * sizeof(Line)); + + bot = MIN(ny, row - 1); + scr = MAX(row - term.row, 0); + /* update y coordinate of cursor line end */ + nce = MIN(oce + scr, bot); + /* update cursor y coordinate */ + term.c.y = nce - (ny - cy); + if (term.c.y < 0) { + j = nce, nce = MIN(nce + -term.c.y, bot); + term.c.y += nce - j; + while (term.c.y < 0) { + free(buf[ny--]); + term.c.y++; + } } - /* 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 new rows */ + for (i = row - 1; i > nce; i--) { + term.line[i] = xmalloc(col * sizeof(Glyph)); + for (j = 0; j < col; j++) + tclearglyph(&term.line[i][j], 0); } - for (i += row; i < term.row; i++) { + /* fill visible area */ + for (/*i = nce */; i >= term.row; i--, ny--) + term.line[i] = buf[ny]; + for (/*i = term.row - 1 */; i >= 0; i--, ny--) { free(term.line[i]); - free(term.alt[i]); + term.line[i] = buf[ny]; + } + /* fill lines in history buffer and update term.histf */ + for (/*i = -1 */; ny >= 0 && i >= -HISTSIZE; i--, ny--) { + j = (term.histi + i + 1 + HISTSIZE) % HISTSIZE; + free(term.hist[j]); + term.hist[j] = buf[ny]; + } + term.histf = -i - 1; + term.scr = MIN(term.scr, term.histf); + /* resize rest of the history lines */ + for (/*i = -term.histf - 1 */; i >= -HISTSIZE; i--) { + j = (term.histi + i + 1 + HISTSIZE) % HISTSIZE; + term.hist[j] = xrealloc(term.hist[j], col * sizeof(Glyph)); } + free(buf); +} - /* 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)); +void +rscrolldown(int n) +{ + int i; + Line temp; - /* 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)); - } + /* can never be true as of now + if (IS_SET(MODE_ALTSCREEN)) + return; */ - /* 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 ((n = MIN(n, term.histf)) <= 0) + return; + + for (i = term.c.y + n; i >= n; i--) { + temp = term.line[i]; + term.line[i] = term.line[i-n]; + term.line[i-n] = temp; + } + for (/*i = n - 1 */; i >= 0; i--) { + temp = term.line[i]; + term.line[i] = term.hist[term.histi]; + term.hist[term.histi] = temp; + term.histi = (term.histi - 1 + HISTSIZE) % HISTSIZE; + } + term.c.y += n; + term.histf -= n; + if ((i = term.scr - n) >= 0) { + term.scr = i; + } else { + term.scr = 0; + if (sel.ob.x != -1 && !sel.alt) + selmove(-i); } +} + +void +tresize(int col, int row) +{ + int *bp; + + /* col and row are always MAX(_, 1) + if (col < 1 || row < 1) { + fprintf(stderr, "tresize: error resizing to %dx%d\n", col, row); + return; + } */ + + term.dirty = xrealloc(term.dirty, row * sizeof(*term.dirty)); + term.tabs = xrealloc(term.tabs, col * sizeof(*term.tabs)); if (col > term.col) { bp = term.tabs + term.col; - memset(bp, 0, sizeof(*term.tabs) * (col - term.col)); while (--bp > term.tabs && !*bp) /* nothing */ ; for (bp += tabspaces; bp < term.tabs + col; bp += tabspaces) *bp = 1; } - /* update terminal size */ - term.col = col; - term.row = row; - /* 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 (IS_SET(MODE_ALTSCREEN)) + tresizealt(col, row); + else + tresizedef(col, row); +} + +void +tresizedef(int col, int row) +{ + int i, j; + + /* return if dimensions haven't changed */ + if (term.col == col && term.row == row) { + tfulldirt(); + return; + } + if (col != term.col) { + if (!sel.alt) + selremove(); + treflow(col, row); + } else { + /* slide screen up if otherwise cursor would get out of the screen */ + if (term.c.y >= row) { + tscrollup(0, term.row - 1, term.c.y - row + 1, SCROLL_RESIZE); + term.c.y = row - 1; } - if (0 < col && minrow < row) { - tclearregion(0, minrow, col - 1, row - 1); + for (i = row; i < term.row; i++) + free(term.line[i]); + + /* resize to new height */ + term.line = xrealloc(term.line, row * sizeof(Line)); + /* allocate any new rows */ + for (i = term.row; i < row; i++) { + term.line[i] = xmalloc(col * sizeof(Glyph)); + for (j = 0; j < col; j++) + tclearglyph(&term.line[i][j], 0); } - tswapscreen(); - tcursor(CURSOR_LOAD); + /* scroll down as much as height has increased */ + rscrolldown(row - term.row); + } + /* update terminal size */ + term.col = col, term.row = row; + /* reset scrolling region */ + term.top = 0, term.bot = row - 1; + /* dirty all lines */ + tfulldirt(); +} + +void +tresizealt(int col, int row) +{ + int i, j; + + /* return if dimensions haven't changed */ + if (term.col == col && term.row == row) { + tfulldirt(); + return; } - term.c = c; + if (sel.alt) + selremove(); + /* slide screen up if otherwise cursor would get out of the screen */ + for (i = 0; i <= term.c.y - row; i++) + free(term.line[i]); + if (i > 0) { + /* ensure that both src and dst are not NULL */ + memmove(term.line, term.line + i, row * sizeof(Line)); + term.c.y = row - 1; + } + for (i += row; i < term.row; i++) + free(term.line[i]); + /* resize to new height */ + term.line = xrealloc(term.line, row * sizeof(Line)); + /* resize to new width */ + for (i = 0; i < MIN(row, term.row); i++) { + term.line[i] = xrealloc(term.line[i], col * sizeof(Glyph)); + for (j = term.col; j < col; j++) + tclearglyph(&term.line[i][j], 0); + } + /* allocate any new rows */ + for (/*i = MIN(row, term.row) */; i < row; i++) { + term.line[i] = xmalloc(col * sizeof(Glyph)); + for (j = 0; j < col; j++) + tclearglyph(&term.line[i][j], 0); + } + /* update cursor */ + if (term.c.x >= col) { + term.c.state &= ~CURSOR_WRAPNEXT; + term.c.x = col - 1; + } else { + UPDATEWRAPNEXT(1, col); + } + /* update terminal size */ + term.col = col, term.row = row; + /* reset scrolling region */ + term.top = 0, term.bot = row - 1; + /* dirty all lines */ + tfulldirt(); } void @@ -2652,7 +3070,7 @@ drawregion(int x1, int y1, int x2, int y2) continue; term.dirty[y] = 0; - xdrawline(term.line[y], x1, y, x2); + xdrawline(TLINE(y), x1, y, x2); } } diff --git a/st.h b/st.h index 519b9bd..2e3eb6c 100644 --- a/st.h +++ b/st.h @@ -22,17 +22,19 @@ enum glyph_attribute { ATTR_NULL = 0, - ATTR_BOLD = 1 << 0, - ATTR_FAINT = 1 << 1, - ATTR_ITALIC = 1 << 2, - ATTR_UNDERLINE = 1 << 3, - ATTR_BLINK = 1 << 4, - ATTR_REVERSE = 1 << 5, - ATTR_INVISIBLE = 1 << 6, - ATTR_STRUCK = 1 << 7, - ATTR_WRAP = 1 << 8, - ATTR_WIDE = 1 << 9, - ATTR_WDUMMY = 1 << 10, + ATTR_SET = 1 << 0, + ATTR_BOLD = 1 << 1, + ATTR_FAINT = 1 << 2, + ATTR_ITALIC = 1 << 3, + ATTR_UNDERLINE = 1 << 4, + ATTR_BLINK = 1 << 5, + ATTR_REVERSE = 1 << 6, + ATTR_INVISIBLE = 1 << 7, + ATTR_STRUCK = 1 << 8, + ATTR_WRAP = 1 << 9, + ATTR_WIDE = 1 << 10, + ATTR_WDUMMY = 1 << 11, + ATTR_SELECTED = 1 << 12, ATTR_BOLD_FAINT = ATTR_BOLD | ATTR_FAINT, }; @@ -81,6 +83,8 @@ void die(const char *, ...); void redraw(void); void draw(void); +void kscrolldown(const Arg *); +void kscrollup(const Arg *); void printscreen(const Arg *); void printsel(const Arg *); void sendbreak(const Arg *); @@ -88,6 +92,7 @@ void toggleprinter(const Arg *); int tattrset(int); void tnew(int, int); +int tisaltscreen(void); void tresize(int, int); void tsetdirtattr(int); void ttyhangup(void); -- cgit v1.2.3 From 0fa2f8bfe053c36de873a23a1e54f2ad7eca097a Mon Sep 17 00:00:00 2001 From: Aiden Gall Date: Thu, 16 Nov 2023 02:35:15 +0000 Subject: patch alpha --- config.def.h | 2 ++ config.mk | 2 +- st.h | 1 + x.c | 40 ++++++++++++++++++++++++++++++---------- 4 files changed, 34 insertions(+), 11 deletions(-) diff --git a/config.def.h b/config.def.h index e3b469b..dff6275 100644 --- a/config.def.h +++ b/config.def.h @@ -93,6 +93,8 @@ char *termname = "st-256color"; */ unsigned int tabspaces = 8; +float alpha = 0.8; + /* Terminal colors (16 first used in escape sequence) */ static const char *colorname[] = { /* 8 normal colors */ diff --git a/config.mk b/config.mk index 4c4c5d5..355db98 100644 --- a/config.mk +++ b/config.mk @@ -16,7 +16,7 @@ PKG_CONFIG = pkg-config INCS = -I$(X11INC) \ `$(PKG_CONFIG) --cflags fontconfig` \ `$(PKG_CONFIG) --cflags freetype2` -LIBS = -L$(X11LIB) -lm -lrt -lX11 -lutil -lXft \ +LIBS = -L$(X11LIB) -lm -lrt -lX11 -lutil -lXft -lXrender \ `$(PKG_CONFIG) --libs fontconfig` \ `$(PKG_CONFIG) --libs freetype2` diff --git a/st.h b/st.h index 2e3eb6c..39f1425 100644 --- a/st.h +++ b/st.h @@ -131,3 +131,4 @@ extern unsigned int tabspaces; extern unsigned int defaultfg; extern unsigned int defaultbg; extern unsigned int defaultcs; +extern float alpha; diff --git a/x.c b/x.c index 8a16faa..ddf4178 100644 --- a/x.c +++ b/x.c @@ -105,6 +105,7 @@ typedef struct { XSetWindowAttributes attrs; int scr; int isfixed; /* is fixed geometry? */ + int depth; /* bit depth */ int l, t; /* left and top offset */ int gm; /* geometry mask */ } XWindow; @@ -243,6 +244,7 @@ static char *usedfont = NULL; static double usedfontsize = 0; static double defaultfontsize = 0; +static char *opt_alpha = NULL; static char *opt_class = NULL; static char **opt_cmd = NULL; static char *opt_embed = NULL; @@ -736,7 +738,7 @@ xresize(int col, int row) XFreePixmap(xw.dpy, xw.buf); xw.buf = XCreatePixmap(xw.dpy, xw.win, win.w, win.h, - DefaultDepth(xw.dpy, xw.scr)); + xw.depth); XftDrawChange(xw.draw, xw.buf); xclear(0, 0, win.w, win.h); @@ -796,6 +798,13 @@ xloadcols(void) else die("could not allocate color %d\n", i); } + + /* set alpha value of bg color */ + if (opt_alpha) + alpha = strtof(opt_alpha, NULL); + dc.col[defaultbg].color.alpha = (unsigned short)(0xffff * alpha); + dc.col[defaultbg].pixel &= 0x00FFFFFF; + dc.col[defaultbg].pixel |= (unsigned char)(0xff * alpha) << 24; loaded = 1; } @@ -1118,11 +1127,23 @@ xinit(int cols, int rows) Window parent; pid_t thispid = getpid(); XColor xmousefg, xmousebg; + XWindowAttributes attr; + XVisualInfo vis; if (!(xw.dpy = XOpenDisplay(NULL))) die("can't open display\n"); xw.scr = XDefaultScreen(xw.dpy); - xw.vis = XDefaultVisual(xw.dpy, xw.scr); + + if (!(opt_embed && (parent = strtol(opt_embed, NULL, 0)))) { + parent = XRootWindow(xw.dpy, xw.scr); + xw.depth = 32; + } else { + XGetWindowAttributes(xw.dpy, parent, &attr); + xw.depth = attr.depth; + } + + XMatchVisualInfo(xw.dpy, xw.scr, xw.depth, TrueColor, &vis); + xw.vis = vis.visual; /* font */ if (!FcInit()) @@ -1132,7 +1153,7 @@ xinit(int cols, int rows) xloadfonts(usedfont, 0); /* colors */ - xw.cmap = XDefaultColormap(xw.dpy, xw.scr); + xw.cmap = XCreateColormap(xw.dpy, parent, xw.vis, None); xloadcols(); /* adjust fixed window geometry */ @@ -1152,19 +1173,15 @@ xinit(int cols, int rows) | ButtonMotionMask | ButtonPressMask | ButtonReleaseMask; xw.attrs.colormap = xw.cmap; - 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, - win.w, win.h, 0, XDefaultDepth(xw.dpy, xw.scr), InputOutput, + win.w, win.h, 0, xw.depth, InputOutput, xw.vis, CWBackPixel | CWBorderPixel | CWBitGravity | CWEventMask | CWColormap, &xw.attrs); memset(&gcvalues, 0, sizeof(gcvalues)); 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 = XCreatePixmap(xw.dpy, xw.win, win.w, win.h, xw.depth); + dc.gc = XCreateGC(xw.dpy, xw.buf, GCGraphicsExposures, &gcvalues); XSetForeground(xw.dpy, dc.gc, dc.col[defaultbg].pixel); XFillRectangle(xw.dpy, xw.buf, dc.gc, 0, 0, win.w, win.h); @@ -2019,6 +2036,9 @@ main(int argc, char *argv[]) case 'a': allowaltscreen = 0; break; + case 'A': + opt_alpha = EARGF(usage()); + break; case 'c': opt_class = EARGF(usage()); break; -- cgit v1.2.3 From 425fceb39d64b88dc3fc4c6715ccef64ad4a0897 Mon Sep 17 00:00:00 2001 From: Aiden Gall Date: Thu, 16 Nov 2023 03:19:37 +0000 Subject: add my configuration --- config.def.h | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/config.def.h b/config.def.h index dff6275..5dd7204 100644 --- a/config.def.h +++ b/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 = "mono:pixelsize=14:antialias=true:autohint=true"; static int borderpx = 2; /* @@ -178,6 +178,8 @@ static uint forcemousemod = ShiftMask; */ static MouseShortcut mshortcuts[] = { /* mask button function argument release */ + { XK_NO_MOD, Button4, kscrollup, {.i = 1} }, + { XK_NO_MOD, Button5, kscrolldown, {.i = 1} }, { XK_ANY_MOD, Button2, selpaste, {.i = 0}, 1 }, { ShiftMask, Button4, ttysend, {.s = "\033[5;2~"} }, { XK_ANY_MOD, Button4, ttysend, {.s = "\031"} }, @@ -187,7 +189,7 @@ static MouseShortcut mshortcuts[] = { /* Internal keyboard shortcuts. */ #define MODKEY Mod1Mask -#define TERMMOD (ControlMask|ShiftMask) +#define TERMMOD (Mod1Mask|ShiftMask) static Shortcut shortcuts[] = { /* mask keysym function argument */ @@ -200,11 +202,27 @@ static Shortcut shortcuts[] = { { TERMMOD, XK_Home, zoomreset, {.f = 0} }, { TERMMOD, XK_C, clipcopy, {.i = 0} }, { TERMMOD, XK_V, clippaste, {.i = 0} }, - { TERMMOD, XK_Y, selpaste, {.i = 0} }, + { MODKEY, XK_c, clipcopy, {.i = 0} }, + { ShiftMask, XK_Insert, clippaste, {.i = 0} }, + { MODKEY, XK_v, clippaste, {.i = 0} }, { ShiftMask, XK_Insert, selpaste, {.i = 0} }, { TERMMOD, XK_Num_Lock, numlock, {.i = 0} }, { ShiftMask, XK_Page_Up, kscrollup, {.i = -1} }, { ShiftMask, XK_Page_Down, kscrolldown, {.i = -1} }, + { MODKEY, XK_Page_Up, kscrollup, {.i = -1} }, + { MODKEY, XK_Page_Down, kscrolldown, {.i = -1} }, + { MODKEY, XK_k, kscrollup, {.i = 1} }, + { MODKEY, XK_j, kscrolldown, {.i = 1} }, + { MODKEY, XK_Up, kscrollup, {.i = 1} }, + { MODKEY, XK_Down, kscrolldown, {.i = 1} }, + { MODKEY, XK_u, kscrollup, {.i = -1} }, + { MODKEY, XK_d, kscrolldown, {.i = -1} }, + { TERMMOD, XK_Up, zoom, {.f = +1} }, + { TERMMOD, XK_Down, zoom, {.f = -1} }, + { TERMMOD, XK_K, zoom, {.f = +1} }, + { TERMMOD, XK_J, zoom, {.f = -1} }, + { TERMMOD, XK_U, zoom, {.f = +2} }, + { TERMMOD, XK_D, zoom, {.f = -2} }, }; /* -- cgit v1.2.3 From ccea59806e190d44d6fceb782a2a894b13257e42 Mon Sep 17 00:00:00 2001 From: Aiden Gall Date: Thu, 16 Nov 2023 04:10:21 +0000 Subject: merge commits ea7cd7b through 9846a56 from master --- FAQ | 9 ++-- LICENSE | 2 +- Makefile | 10 +---- config.mk | 3 +- st.c | 150 ++++++++++++++++++++++++++++---------------------------------- st.h | 2 - st.info | 4 ++ win.h | 1 + x.c | 103 ++++++++++++++++++++++++------------------ 9 files changed, 144 insertions(+), 140 deletions(-) diff --git a/FAQ b/FAQ index 969b195..1a2b1b4 100644 --- a/FAQ +++ b/FAQ @@ -192,13 +192,13 @@ diff --git 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; @@ -209,7 +209,7 @@ diff --git a/x.c b/x.c + 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) @@ -248,3 +248,6 @@ fonts: Please don't bother reporting this bug to st, but notify the upstream Xft developers about fixing this bug. + +As of 2022-09-05 this now seems to be finally fixed in libXft 2.3.5: +https://gitlab.freedesktop.org/xorg/lib/libxft/-/blob/libXft-2.3.5/NEWS diff --git a/LICENSE b/LICENSE index d80eb47..3cbf420 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT/X Consortium License -© 2014-2020 Hiltjo Posthuma +© 2014-2022 Hiltjo Posthuma © 2018 Devin J. Pohly © 2014-2017 Quentin Rameau © 2009-2012 Aurélien APTEL diff --git a/Makefile b/Makefile index 470ac86..15db421 100644 --- a/Makefile +++ b/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 diff --git a/config.mk b/config.mk index 355db98..c35bad1 100644 --- a/config.mk +++ b/config.mk @@ -1,5 +1,5 @@ # st version -VERSION = 0.8.5 +VERSION = 0.9 # Customize below to fit your system @@ -30,6 +30,7 @@ STLDFLAGS = $(LIBS) $(LDFLAGS) #LIBS = -L$(X11LIB) -lm -lX11 -lutil -lXft \ # `$(PKG_CONFIG) --libs fontconfig` \ # `$(PKG_CONFIG) --libs freetype2` +#MANPREFIX = ${PREFIX}/man # compiler and linker # CC = c99 diff --git a/st.c b/st.c index 230ef3a..4a5f88e 100644 --- a/st.c +++ b/st.c @@ -189,6 +189,7 @@ static void csidump(void); static void csihandle(void); static void csiparse(void); static void csireset(void); +static void osc_color_response(int, int, int); static int eschandle(uchar); static void strdump(void); static void strhandle(void); @@ -391,25 +392,10 @@ utf8validate(Rune *u, size_t i) return i; } -static const char base64_digits[] = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 62, 0, 0, 0, - 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 0, 0, 0, -1, 0, 0, 0, 0, 1, - 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, - 22, 23, 24, 25, 0, 0, 0, 0, 0, 0, 26, 27, 28, 29, 30, 31, 32, 33, 34, - 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 -}; - char base64dec_getc(const char **src) { - while (**src && !isprint(**src)) + while (**src && !isprint((unsigned char)**src)) (*src)++; return **src ? *((*src)++) : '='; /* emulate padding if string ends */ } @@ -419,6 +405,13 @@ base64dec(const char *src) { size_t in_len = strlen(src); char *result, *dst; + static const char base64_digits[256] = { + [43] = 62, 0, 0, 0, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, + 0, 0, 0, -1, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, + 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 0, 0, 0, 0, + 0, 0, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, + 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51 + }; if (in_len % 4) in_len += 4 - (in_len % 4); @@ -1022,7 +1015,7 @@ ttyresize(int tw, int th) } void -ttyhangup() +ttyhangup(void) { /* Send SIGHUP to shell */ kill(pid, SIGHUP); @@ -2010,11 +2003,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) ";R" */ n = snprintf(buf, sizeof(buf), "\033[%i;%iR", - term.c.y+1, term.c.x+1); + term.c.y+1, term.c.x+1); ttywrite(buf, n, 0); + break; + default: + goto unknown; } break; case 'r': /* DECSTBM -- Set Scrolling Region */ @@ -2077,39 +2077,28 @@ csireset(void) } void -osc4_color_response(int num) +osc_color_response(int num, int index, int is_osc4) { int n; char buf[32]; unsigned char r, g, b; - if (xgetcolor(num, &r, &g, &b)) { - fprintf(stderr, "erresc: failed to fetch osc4 color %d\n", num); + if (xgetcolor(is_osc4 ? num : index, &r, &g, &b)) { + fprintf(stderr, "erresc: failed to fetch %s color %d\n", + is_osc4 ? "osc4" : "osc", + is_osc4 ? num : index); return; } - n = snprintf(buf, sizeof buf, "\033]4;%d;rgb:%02x%02x/%02x%02x/%02x%02x\007", - num, r, r, g, g, b, b); - - ttywrite(buf, n, 1); -} - -void -osc_color_response(int index, int num) -{ - int n; - char buf[32]; - unsigned char r, g, b; - - if (xgetcolor(index, &r, &g, &b)) { - fprintf(stderr, "erresc: failed to fetch osc color %d\n", index); - return; + n = snprintf(buf, sizeof buf, "\033]%s%d;rgb:%02x%02x/%02x%02x/%02x%02x\007", + is_osc4 ? "4;" : "", num, r, r, g, g, b, b); + if (n < 0 || n >= sizeof(buf)) { + fprintf(stderr, "error: %s while printing %s response\n", + n < 0 ? "snprintf failed" : "truncation occurred", + is_osc4 ? "osc4" : "osc"); + } else { + ttywrite(buf, n, 1); } - - n = snprintf(buf, sizeof buf, "\033]%d;rgb:%02x%02x/%02x%02x/%02x%02x\007", - num, r, r, g, g, b, b); - - ttywrite(buf, n, 1); } void @@ -2117,6 +2106,11 @@ strhandle(void) { char *p = NULL, *dec; int j, narg, par; + const struct { int idx; char *str; } osc_table[] = { + { defaultfg, "foreground" }, + { defaultbg, "background" }, + { defaultcs, "cursor" } + }; term.esc &= ~(ESC_STR_END|ESC_STR); strparse(); @@ -2151,43 +2145,22 @@ strhandle(void) } return; case 10: - if (narg < 2) - break; - - p = strescseq.args[1]; - - if (!strcmp(p, "?")) - osc_color_response(defaultfg, 10); - else if (xsetcolorname(defaultfg, p)) - fprintf(stderr, "erresc: invalid foreground color: %s\n", p); - else - redraw(); - return; case 11: - if (narg < 2) - break; - - p = strescseq.args[1]; - - if (!strcmp(p, "?")) - osc_color_response(defaultbg, 11); - else if (xsetcolorname(defaultbg, p)) - fprintf(stderr, "erresc: invalid background color: %s\n", p); - else - redraw(); - return; case 12: if (narg < 2) break; - p = strescseq.args[1]; - - if (!strcmp(p, "?")) - osc_color_response(defaultcs, 12); - else if (xsetcolorname(defaultcs, p)) - fprintf(stderr, "erresc: invalid cursor color: %s\n", p); - else - redraw(); + if ((j = par - 10) < 0 || j >= LEN(osc_table)) + break; /* shouldn't be possible */ + + if (!strcmp(p, "?")) { + osc_color_response(par, osc_table[j].idx, 0); + } else if (xsetcolorname(osc_table[j].idx, p)) { + fprintf(stderr, "erresc: invalid %s color: %s\n", + osc_table[j].str, p); + } else { + tfulldirt(); + } return; case 4: /* color set */ if (narg < 3) @@ -2197,11 +2170,13 @@ strhandle(void) case 104: /* color reset */ j = (narg > 1) ? atoi(strescseq.args[1]) : -1; - if (p && !strcmp(p, "?")) - osc4_color_response(j); - else if (xsetcolorname(j, p)) { - if (par == 104 && narg <= 1) + if (p && !strcmp(p, "?")) { + osc_color_response(j, 0, 1); + } else if (xsetcolorname(j, p)) { + if (par == 104 && narg <= 1) { + xloadcols(); return; /* color reset without parameter */ + } fprintf(stderr, "erresc: invalid color j=%d, p=%s\n", j, p ? p : "(null)"); } else { @@ -2209,7 +2184,7 @@ strhandle(void) * TODO if defaultbg color is changed, borders * are dirty */ - redraw(); + tfulldirt(); } return; } @@ -2581,6 +2556,7 @@ eschandle(uchar ascii) treset(); resettitle(); xloadcols(); + xsetmode(0, MODE_HIDE); break; case '=': /* DECPAM -- Application keypad */ xsetmode(1, MODE_APPKEYPAD); @@ -2673,6 +2649,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 @@ -2720,11 +2699,16 @@ check_control_code: gp = &term.line[term.c.y][term.c.x]; } - if (IS_SET(MODE_INSERT) && term.c.x+width < term.col) + if (IS_SET(MODE_INSERT) && term.c.x+width < term.col) { memmove(gp+width, gp, (term.col - term.c.x - width) * sizeof(Glyph)); + gp->mode &= ~ATTR_WIDE; + } if (term.c.x+width > term.col) { - tnewline(1); + if (IS_SET(MODE_WRAP)) + tnewline(1); + else + tmoveto(term.col - width, term.c.y); gp = &term.line[term.c.y][term.c.x]; } diff --git a/st.h b/st.h index 39f1425..73903f6 100644 --- a/st.h +++ b/st.h @@ -116,8 +116,6 @@ void *xmalloc(size_t); void *xrealloc(void *, size_t); char *xstrdup(const char *); -int xgetcolor(int x, unsigned char *r, unsigned char *g, unsigned char *b); - /* config.h globals */ extern char *utmp; extern char *scroll; diff --git a/st.info b/st.info index 8201ad6..efab2cf 100644 --- a/st.info +++ b/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) diff --git a/win.h b/win.h index e6e4369..6de960d 100644 --- a/win.h +++ b/win.h @@ -30,6 +30,7 @@ void xdrawline(Line, int, int, int); void xfinishdraw(void); void xloadcols(void); int xsetcolorname(int, const char *); +int xgetcolor(int, unsigned char *, unsigned char *, unsigned char *); void xseticontitle(char *); void xsettitle(char *); int xsetcursor(int); diff --git a/x.c b/x.c index ddf4178..9c98b8d 100644 --- a/x.c +++ b/x.c @@ -254,7 +254,7 @@ static char *opt_line = NULL; static char *opt_name = NULL; static char *opt_title = NULL; -static int oldbutton = 3; /* button event on startup: 3 = release */ +static uint buttons; /* bit field of pressed buttons */ void clipcopy(const Arg *dummy) @@ -366,61 +366,68 @@ mousesel(XEvent *e, int done) void mousereport(XEvent *e) { - int len, x = evcol(e), y = evrow(e), - button = e->xbutton.button, state = e->xbutton.state; + int len, btn, code; + int x = evcol(e), y = evrow(e); + int state = e->xbutton.state; char buf[40]; static int ox, oy; - /* from urxvt */ - if (e->xbutton.type == MotionNotify) { + if (e->type == MotionNotify) { if (x == ox && y == oy) return; if (!IS_SET(MODE_MOUSEMOTION) && !IS_SET(MODE_MOUSEMANY)) return; - /* MOUSE_MOTION: no reporting if no button is pressed */ - if (IS_SET(MODE_MOUSEMOTION) && oldbutton == 3) + /* MODE_MOUSEMOTION: no reporting if no button is pressed */ + if (IS_SET(MODE_MOUSEMOTION) && buttons == 0) return; - - button = oldbutton + 32; - ox = x; - oy = y; + /* Set btn to lowest-numbered pressed button, or 12 if no + * buttons are pressed. */ + for (btn = 1; btn <= 11 && !(buttons & (1<<(btn-1))); btn++) + ; + code = 32; } else { - if (!IS_SET(MODE_MOUSESGR) && e->xbutton.type == ButtonRelease) { - button = 3; - } else { - button -= Button1; - if (button >= 7) - button += 128 - 7; - else if (button >= 3) - button += 64 - 3; - } - if (e->xbutton.type == ButtonPress) { - oldbutton = button; - ox = x; - oy = y; - } else if (e->xbutton.type == ButtonRelease) { - oldbutton = 3; + btn = e->xbutton.button; + /* Only buttons 1 through 11 can be encoded */ + if (btn < 1 || btn > 11) + return; + if (e->type == ButtonRelease) { /* MODE_MOUSEX10: no button release reporting */ if (IS_SET(MODE_MOUSEX10)) return; - if (button == 64 || button == 65) + /* Don't send release events for the scroll wheel */ + if (btn == 4 || btn == 5) return; } + code = 0; } + ox = x; + oy = y; + + /* Encode btn into code. If no button is pressed for a motion event in + * MODE_MOUSEMANY, then encode it as a release. */ + if ((!IS_SET(MODE_MOUSESGR) && e->type == ButtonRelease) || btn == 12) + code += 3; + else if (btn >= 8) + code += 128 + btn - 8; + else if (btn >= 4) + code += 64 + btn - 4; + else + code += btn - 1; + if (!IS_SET(MODE_MOUSEX10)) { - button += ((state & ShiftMask ) ? 4 : 0) - + ((state & Mod4Mask ) ? 8 : 0) - + ((state & ControlMask) ? 16 : 0); + code += ((state & ShiftMask ) ? 4 : 0) + + ((state & Mod1Mask ) ? 8 : 0) /* meta key: alt */ + + ((state & ControlMask) ? 16 : 0); } if (IS_SET(MODE_MOUSESGR)) { len = snprintf(buf, sizeof(buf), "\033[<%d;%d;%d%c", - button, x+1, y+1, - e->xbutton.type == ButtonRelease ? 'm' : 'M'); + code, x+1, y+1, + e->type == ButtonRelease ? 'm' : 'M'); } else if (x < 223 && y < 223) { len = snprintf(buf, sizeof(buf), "\033[M%c%c%c", - 32+button, 32+x+1, 32+y+1); + 32+code, 32+x+1, 32+y+1); } else { return; } @@ -463,9 +470,13 @@ mouseaction(XEvent *e, uint release) void bpress(XEvent *e) { + int btn = e->xbutton.button; struct timespec now; int snap; + if (1 <= btn && btn <= 11) + buttons |= 1 << (btn-1); + if (IS_SET(MODE_MOUSE) && !(e->xbutton.state & forcemousemod)) { mousereport(e); return; @@ -474,7 +485,7 @@ bpress(XEvent *e) if (mouseaction(e, 0)) return; - if (e->xbutton.button == Button1) { + if (btn == Button1) { /* * If the user clicks below predefined timeouts specific * snapping behaviour is exposed. @@ -688,6 +699,11 @@ xsetsel(char *str) void brelease(XEvent *e) { + int btn = e->xbutton.button; + + if (1 <= btn && btn <= 11) + buttons &= ~(1 << (btn-1)); + if (IS_SET(MODE_MOUSE) && !(e->xbutton.state & forcemousemod)) { mousereport(e); return; @@ -695,7 +711,7 @@ brelease(XEvent *e) if (mouseaction(e, 1)) return; - if (e->xbutton.button == Button1) + if (btn == Button1) mousesel(e, 1); } @@ -811,7 +827,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; @@ -826,7 +842,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)) @@ -1494,12 +1510,12 @@ xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, i /* Render underline and strikethrough. */ if (base.mode & ATTR_UNDERLINE) { - XftDrawRect(xw.draw, fg, winx, winy + dc.font.ascent + 1, + XftDrawRect(xw.draw, fg, winx, winy + dc.font.ascent * chscale + 1, width, 1); } if (base.mode & ATTR_STRUCK) { - XftDrawRect(xw.draw, fg, winx, winy + 2 * dc.font.ascent / 3, + XftDrawRect(xw.draw, fg, winx, winy + 2 * dc.font.ascent * chscale / 3, width, 1); } @@ -1834,7 +1850,7 @@ void kpress(XEvent *ev) { XKeyEvent *e = &ev->xkey; - KeySym ksym; + KeySym ksym = NoSymbol; char buf[64], *customkey; int len; Rune c; @@ -1844,10 +1860,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)) { -- cgit v1.2.3 From 2dc24266f65d0f707c5a77ddb1f63473198203cd Mon Sep 17 00:00:00 2001 From: Aiden Gall Date: Thu, 16 Nov 2023 05:01:00 +0000 Subject: patch anysize --- x.c | 56 ++++++++++++++++++++++++++++++-------------------------- 1 file changed, 30 insertions(+), 26 deletions(-) diff --git a/x.c b/x.c index 9c98b8d..2dd63a6 100644 --- a/x.c +++ b/x.c @@ -81,6 +81,7 @@ typedef XftGlyphFontSpec GlyphFontSpec; typedef struct { int tw, th; /* tty width and height */ int w, h; /* window width and height */ + int hborderpx, vborderpx; int ch; /* char height */ int cw; /* char width */ int mode; /* window state/mode flags */ @@ -333,7 +334,7 @@ ttysend(const Arg *arg) int evcol(XEvent *e) { - int x = e->xbutton.x - borderpx; + int x = e->xbutton.x - win.hborderpx; LIMIT(x, 0, win.tw - 1); return x / win.cw; } @@ -341,7 +342,7 @@ evcol(XEvent *e) int evrow(XEvent *e) { - int y = e->xbutton.y - borderpx; + int y = e->xbutton.y - win.vborderpx; LIMIT(y, 0, win.th - 1); return y / win.ch; } @@ -741,6 +742,9 @@ cresize(int width, int height) col = MAX(1, col); row = MAX(1, row); + win.hborderpx = (win.w - col * win.cw) / 2; + win.vborderpx = (win.h - row * win.ch) / 2; + tresize(col, row); xresize(col, row); ttyresize(win.tw, win.th); @@ -878,8 +882,8 @@ xhints(void) sizeh->flags = PSize | PResizeInc | PBaseSize | PMinSize; sizeh->height = win.h; sizeh->width = win.w; - sizeh->height_inc = win.ch; - sizeh->width_inc = win.cw; + sizeh->height_inc = 1; + sizeh->width_inc = 1; sizeh->base_height = 2 * borderpx; sizeh->base_width = 2 * borderpx; sizeh->min_height = win.ch + 2 * borderpx; @@ -1173,8 +1177,8 @@ xinit(int cols, int rows) xloadcols(); /* adjust fixed window geometry */ - win.w = 2 * borderpx + cols * win.cw; - win.h = 2 * borderpx + rows * win.ch; + win.w = 2 * win.hborderpx + 2 * borderpx + cols * win.cw; + win.h = 2 * win.vborderpx + 2 * borderpx + rows * win.ch; if (xw.gm & XNegative) xw.l += DisplayWidth(xw.dpy, xw.scr) - win.w - 2; if (xw.gm & YNegative) @@ -1259,7 +1263,7 @@ xinit(int cols, int rows) int xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x, int y) { - float winx = borderpx + x * win.cw, winy = borderpx + y * win.ch, xp, yp; + float winx = win.hborderpx + x * win.cw, winy = win.vborderpx + y * win.ch, xp, yp; ushort mode, prevmode = USHRT_MAX; Font *font = &dc.font; int frcflags = FRC_NORMAL; @@ -1392,7 +1396,7 @@ void xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, int y) { int charlen = len * ((base.mode & ATTR_WIDE) ? 2 : 1); - int winx = borderpx + x * win.cw, winy = borderpx + y * win.ch, + int winx = win.hborderpx + x * win.cw, winy = win.vborderpx + y * win.ch, width = charlen * win.cw; Color *fg, *bg, *temp, revfg, revbg, truefg, truebg; XRenderColor colfg, colbg; @@ -1482,17 +1486,17 @@ xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, i /* Intelligent cleaning up of the borders. */ if (x == 0) { - xclear(0, (y == 0)? 0 : winy, borderpx, + xclear(0, (y == 0)? 0 : winy, win.hborderpx, winy + win.ch + - ((winy + win.ch >= borderpx + win.th)? win.h : 0)); + ((winy + win.ch >= win.vborderpx + win.th)? win.h : 0)); } - if (winx + width >= borderpx + win.tw) { + if (winx + width >= win.hborderpx + win.tw) { xclear(winx + width, (y == 0)? 0 : winy, win.w, - ((winy + win.ch >= borderpx + win.th)? win.h : (winy + win.ch))); + ((winy + win.ch >= win.vborderpx + win.th)? win.h : (winy + win.ch))); } if (y == 0) - xclear(winx, 0, winx + width, borderpx); - if (winy + win.ch >= borderpx + win.th) + xclear(winx, 0, winx + width, win.vborderpx); + if (winy + win.ch >= win.vborderpx + win.th) xclear(winx, winy + win.ch, winx + width, win.h); /* Clean up the region we want to draw to. */ @@ -1586,35 +1590,35 @@ xdrawcursor(int cx, int cy, Glyph g, int ox, int oy, Glyph og) case 3: /* Blinking Underline */ case 4: /* Steady Underline */ XftDrawRect(xw.draw, &drawcol, - borderpx + cx * win.cw, - borderpx + (cy + 1) * win.ch - \ + win.hborderpx + cx * win.cw, + win.vborderpx + (cy + 1) * win.ch - \ cursorthickness, win.cw, cursorthickness); break; case 5: /* Blinking bar */ case 6: /* Steady bar */ XftDrawRect(xw.draw, &drawcol, - borderpx + cx * win.cw, - borderpx + cy * win.ch, + win.hborderpx + cx * win.cw, + win.vborderpx + cy * win.ch, cursorthickness, win.ch); break; } } else { XftDrawRect(xw.draw, &drawcol, - borderpx + cx * win.cw, - borderpx + cy * win.ch, + win.hborderpx + cx * win.cw, + win.vborderpx + cy * win.ch, win.cw - 1, 1); XftDrawRect(xw.draw, &drawcol, - borderpx + cx * win.cw, - borderpx + cy * win.ch, + win.hborderpx + cx * win.cw, + win.vborderpx + cy * win.ch, 1, win.ch - 1); XftDrawRect(xw.draw, &drawcol, - borderpx + (cx + 1) * win.cw - 1, - borderpx + cy * win.ch, + win.hborderpx + (cx + 1) * win.cw - 1, + win.vborderpx + cy * win.ch, 1, win.ch - 1); XftDrawRect(xw.draw, &drawcol, - borderpx + cx * win.cw, - borderpx + (cy + 1) * win.ch - 1, + win.hborderpx + cx * win.cw, + win.vborderpx + (cy + 1) * win.ch - 1, win.cw, 1); } } -- cgit v1.2.3 From 9d5d2c66ff51eb021137f71b6a672ba102d297fd Mon Sep 17 00:00:00 2001 From: Aiden Gall Date: Thu, 16 Nov 2023 05:08:22 +0000 Subject: document keybinds in manual --- st.1 | 40 +++++++++++++++++++++------------------- 1 file changed, 21 insertions(+), 19 deletions(-) diff --git a/st.1 b/st.1 index 39120b4..89b16b6 100644 --- a/st.1 +++ b/st.1 @@ -125,6 +125,27 @@ and all the remaining arguments are used as a command even without it. .SH SHORTCUTS .TP +.B Alt-j/k or Alt-Up/Down or Alt-Mouse Wheel +Scroll up/down one line at a time. +.TP +.B Alt-u/d or Alt-Page Up/Page Down +Scroll up/down one screen at a time. +.TP +.B Alt-Shift-k/j or Alt-Shift-Page Up/Page Down or Alt-Shift-Mouse Wheel +Increase or decrease font size. +.TP +.B Alt-Home +Reset to default font size. +.TP +.B Shift-Insert or Alt-v +Paste from clipboard. +.TP +.B Alt-c +Copy to clipboard. +.TP +.B Alt-p +Paste/input primary selection. +.TP .B Break Send a break in the serial line. Break key is obtained in PC keyboards @@ -141,24 +162,6 @@ Print the full screen to the .B Print Screen Print the selection to the .I iofile. -.TP -.B Ctrl-Shift-Page Up -Increase font size. -.TP -.B Ctrl-Shift-Page Down -Decrease font size. -.TP -.B Ctrl-Shift-Home -Reset to default font size. -.TP -.B Ctrl-Shift-y -Paste from primary selection (middle mouse button). -.TP -.B Ctrl-Shift-c -Copy the selected text to the clipboard selection. -.TP -.B Ctrl-Shift-v -Paste from the clipboard selection. .SH CUSTOMIZATION .B st can be customized by creating a custom config.h and (re)compiling the source @@ -174,4 +177,3 @@ See the LICENSE file for the terms of redistribution. .BR scroll (1) .SH BUGS See the TODO file in the distribution. - -- cgit v1.2.3