Compare commits
10 Commits
347f4a9c6d
...
8a78c3eb33
| Author | SHA1 | Date |
|---|---|---|
|
|
8a78c3eb33 | |
|
|
459cbd25f7 | |
|
|
20798c3781 | |
|
|
3f17cb0a1c | |
|
|
9aa9764198 | |
|
|
66c365964b | |
|
|
c471742acf | |
|
|
f3ee21bd5b | |
|
|
2f938c89aa | |
|
|
eb282748e3 |
39
config.def.h
39
config.def.h
|
|
@ -135,13 +135,20 @@ unsigned int defaultcs = 256;
|
|||
static unsigned int defaultrcs = 257;
|
||||
|
||||
/*
|
||||
* Default shape of cursor
|
||||
* 2: Block ("█")
|
||||
* 4: Underline ("_")
|
||||
* 6: Bar ("|")
|
||||
* 7: Snowman ("☃")
|
||||
* https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h4-Functions-using-CSI-_-ordered-by-the-final-character-lparen-s-rparen:CSI-Ps-SP-q.1D81
|
||||
* Default style of cursor
|
||||
* 0: blinking block
|
||||
* 1: blinking block (default)
|
||||
* 2: steady block ("█")
|
||||
* 3: blinking underline
|
||||
* 4: steady underline ("_")
|
||||
* 5: blinking bar
|
||||
* 6: steady bar ("|")
|
||||
* 7: blinking st cursor
|
||||
* 8: steady st cursor
|
||||
*/
|
||||
static unsigned int cursorshape = 2;
|
||||
static unsigned int cursorstyle = 1;
|
||||
static Rune stcursor = 0x2603; /* snowman ("☃") */
|
||||
|
||||
/*
|
||||
* Default columns and rows numbers
|
||||
|
|
@ -170,12 +177,24 @@ static unsigned int defaultattr = 11;
|
|||
*/
|
||||
static uint forcemousemod = ShiftMask;
|
||||
|
||||
/*
|
||||
* The number of lines to scroll by.
|
||||
*/
|
||||
const unsigned int scrollrate = 1;
|
||||
|
||||
/*
|
||||
* The rate to zoom in (adjust the font size).
|
||||
*/
|
||||
const unsigned int zoomrate = 1;
|
||||
|
||||
/*
|
||||
* Internal mouse shortcuts.
|
||||
* Beware that overloading Button1 will disable the selection.
|
||||
*/
|
||||
static MouseShortcut mshortcuts[] = {
|
||||
/* mask button function argument release */
|
||||
{ XK_ANY_MOD, Button4, kscrollup, {.i = scrollrate}, 0, /* !alt */ -1 },
|
||||
{ XK_ANY_MOD, Button5, kscrolldown, {.i = scrollrate}, 0, /* !alt */ -1 },
|
||||
{ XK_ANY_MOD, Button2, selpaste, {.i = 0}, 1 },
|
||||
{ ShiftMask, Button4, ttysend, {.s = "\033[5;2~"} },
|
||||
{ XK_ANY_MOD, Button4, ttysend, {.s = "\031"} },
|
||||
|
|
@ -193,16 +212,16 @@ static Shortcut shortcuts[] = {
|
|||
{ ControlMask, XK_Print, toggleprinter, {.i = 0} },
|
||||
{ ShiftMask, XK_Print, printscreen, {.i = 0} },
|
||||
{ XK_ANY_MOD, XK_Print, printsel, {.i = 0} },
|
||||
{ TERMMOD, XK_Prior, zoom, {.f = +1} },
|
||||
{ TERMMOD, XK_Next, zoom, {.f = -1} },
|
||||
{ TERMMOD, XK_Prior, zoom, {.f = +1 * zoomrate} },
|
||||
{ TERMMOD, XK_Next, zoom, {.f = -1 * zoomrate} },
|
||||
{ TERMMOD, XK_Home, zoomreset, {.f = 0} },
|
||||
{ TERMMOD, XK_C, clipcopy, {.i = 0} },
|
||||
{ TERMMOD, XK_V, clippaste, {.i = 0} },
|
||||
{ TERMMOD, XK_Y, selpaste, {.i = 0} },
|
||||
{ ShiftMask, XK_Insert, selpaste, {.i = 0} },
|
||||
{ TERMMOD, XK_Num_Lock, numlock, {.i = 0} },
|
||||
{ ShiftMask, XK_Page_Up, kscrollup, {.i = -1} },
|
||||
{ ShiftMask, XK_Page_Down, kscrolldown, {.i = -1} },
|
||||
{ ShiftMask, XK_Page_Up, kscrollup, {.i = -1 * scrollrate} },
|
||||
{ ShiftMask, XK_Page_Down, kscrolldown, {.i = -1 * scrollrate} },
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
|
|||
92
st.c
92
st.c
|
|
@ -50,6 +50,10 @@
|
|||
: term.line[(y) - term.scr] \
|
||||
)
|
||||
|
||||
#define TLINE_HIST(y) ( \
|
||||
(y) <= HISTSIZE-term.row+2 ? term.hist[(y)] : term.line[(y-HISTSIZE+term.row-3)] \
|
||||
)
|
||||
|
||||
#define TLINEABS(y) ( \
|
||||
(y) < 0 ? term.hist[(term.histi + (y) + 1 + HISTSIZE) % HISTSIZE] : term.line[(y)] \
|
||||
)
|
||||
|
|
@ -489,6 +493,20 @@ tgetline(char *buf, const Glyph *fgp)
|
|||
return ptr - buf;
|
||||
}
|
||||
|
||||
int
|
||||
tlinehistlen(int y)
|
||||
{
|
||||
int i = term.col;
|
||||
|
||||
if (TLINE_HIST(y)[i - 1].mode & ATTR_WRAP)
|
||||
return i;
|
||||
|
||||
while (i > 0 && TLINE_HIST(y)[i - 1].u == ' ')
|
||||
--i;
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
void
|
||||
selstart(int col, int row, int snap)
|
||||
{
|
||||
|
|
@ -793,8 +811,14 @@ sigchld(int a)
|
|||
if ((p = waitpid(pid, &stat, WNOHANG)) < 0)
|
||||
die("waiting for pid %hd failed: %s\n", pid, strerror(errno));
|
||||
|
||||
if (pid != p)
|
||||
if (pid != p) {
|
||||
if (p == 0 && wait(&stat) < 0)
|
||||
die("wait: %s\n", strerror(errno));
|
||||
|
||||
/* reinstall sigchld handler */
|
||||
signal(SIGCHLD, sigchld);
|
||||
return;
|
||||
}
|
||||
|
||||
if (WIFEXITED(stat) && WEXITSTATUS(stat))
|
||||
die("child exited with status %d\n", WEXITSTATUS(stat));
|
||||
|
|
@ -1063,6 +1087,11 @@ tsetdirtattr(int attr)
|
|||
}
|
||||
}
|
||||
|
||||
int tisaltscr(void)
|
||||
{
|
||||
return IS_SET(MODE_ALTSCREEN);
|
||||
}
|
||||
|
||||
void
|
||||
tfulldirt(void)
|
||||
{
|
||||
|
|
@ -2180,10 +2209,8 @@ strhandle(void)
|
|||
fprintf(stderr, "erresc: invalid color j=%d, p=%s\n",
|
||||
j, p ? p : "(null)");
|
||||
} else {
|
||||
/*
|
||||
* TODO if defaultbg color is changed, borders
|
||||
* are dirty
|
||||
*/
|
||||
if (j == defaultbg)
|
||||
xclearwin();
|
||||
tfulldirt();
|
||||
}
|
||||
return;
|
||||
|
|
@ -2224,6 +2251,61 @@ strparse(void)
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
externalpipe(const Arg *arg)
|
||||
{
|
||||
int to[2];
|
||||
char buf[UTF_SIZ];
|
||||
void (*oldsigpipe)(int);
|
||||
Glyph *bp, *end;
|
||||
int lastpos, n, newline;
|
||||
|
||||
if (pipe(to) == -1)
|
||||
return;
|
||||
|
||||
switch (fork()) {
|
||||
case -1:
|
||||
close(to[0]);
|
||||
close(to[1]);
|
||||
return;
|
||||
case 0:
|
||||
dup2(to[0], STDIN_FILENO);
|
||||
close(to[0]);
|
||||
close(to[1]);
|
||||
execvp(((char **)arg->v)[0], (char **)arg->v);
|
||||
fprintf(stderr, "st: execvp %s\n", ((char **)arg->v)[0]);
|
||||
perror("failed");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
close(to[0]);
|
||||
/* ignore sigpipe for now, in case child exists early */
|
||||
oldsigpipe = signal(SIGPIPE, SIG_IGN);
|
||||
newline = 0;
|
||||
for (n = 0; n <= HISTSIZE + 2; n++) {
|
||||
bp = TLINE_HIST(n);
|
||||
lastpos = MIN(tlinehistlen(n) + 1, term.col) - 1;
|
||||
if (lastpos < 0)
|
||||
break;
|
||||
if (lastpos == 0)
|
||||
continue;
|
||||
end = &bp[lastpos + 1];
|
||||
for (; bp < end; ++bp)
|
||||
if (xwrite(to[1], buf, utf8encode(bp->u, buf)) < 0)
|
||||
break;
|
||||
if ((newline = TLINE_HIST(n)[lastpos].mode & ATTR_WRAP))
|
||||
continue;
|
||||
if (xwrite(to[1], "\n", 1) < 0)
|
||||
break;
|
||||
newline = 0;
|
||||
}
|
||||
if (newline)
|
||||
(void)xwrite(to[1], "\n", 1);
|
||||
close(to[1]);
|
||||
/* restore */
|
||||
signal(SIGPIPE, oldsigpipe);
|
||||
}
|
||||
|
||||
void
|
||||
strdump(void)
|
||||
{
|
||||
|
|
|
|||
2
st.h
2
st.h
|
|
@ -85,12 +85,14 @@ void draw(void);
|
|||
|
||||
void kscrolldown(const Arg *);
|
||||
void kscrollup(const Arg *);
|
||||
void externalpipe(const Arg *);
|
||||
void printscreen(const Arg *);
|
||||
void printsel(const Arg *);
|
||||
void sendbreak(const Arg *);
|
||||
void toggleprinter(const Arg *);
|
||||
|
||||
int tattrset(int);
|
||||
int tisaltscr(void);
|
||||
void tnew(int, int);
|
||||
int tisaltscreen(void);
|
||||
void tresize(int, int);
|
||||
|
|
|
|||
1
win.h
1
win.h
|
|
@ -39,3 +39,4 @@ void xsetpointermotion(int);
|
|||
void xsetsel(char *);
|
||||
int xstartdraw(void);
|
||||
void xximspot(int, int);
|
||||
void xclearwin(void);
|
||||
|
|
|
|||
133
x.c
133
x.c
|
|
@ -14,6 +14,7 @@
|
|||
#include <X11/keysym.h>
|
||||
#include <X11/Xft/Xft.h>
|
||||
#include <X11/XKBlib.h>
|
||||
#include <X11/Xresource.h>
|
||||
|
||||
char *argv0;
|
||||
#include "arg.h"
|
||||
|
|
@ -34,6 +35,7 @@ typedef struct {
|
|||
void (*func)(const Arg *);
|
||||
const Arg arg;
|
||||
uint release;
|
||||
int altscrn; /* 0: don't care, -1: not alt screen, 1: alt screen */
|
||||
} MouseShortcut;
|
||||
|
||||
typedef struct {
|
||||
|
|
@ -45,6 +47,19 @@ typedef struct {
|
|||
signed char appcursor; /* application cursor */
|
||||
} Key;
|
||||
|
||||
/* Xresources preferences */
|
||||
enum resource_type {
|
||||
STRING = 0,
|
||||
INTEGER = 1,
|
||||
FLOAT = 2
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
char *name;
|
||||
enum resource_type type;
|
||||
void *dst;
|
||||
} ResourcePref;
|
||||
|
||||
/* X modifiers */
|
||||
#define XK_ANY_MOD UINT_MAX
|
||||
#define XK_NO_MOD 0
|
||||
|
|
@ -254,6 +269,7 @@ static char *opt_name = NULL;
|
|||
static char *opt_title = NULL;
|
||||
|
||||
static uint buttons; /* bit field of pressed buttons */
|
||||
static int cursorblinks = 0;
|
||||
|
||||
void
|
||||
clipcopy(const Arg *dummy)
|
||||
|
|
@ -456,6 +472,7 @@ mouseaction(XEvent *e, uint release)
|
|||
for (ms = mshortcuts; ms < mshortcuts + LEN(mshortcuts); ms++) {
|
||||
if (ms->release == release &&
|
||||
ms->button == e->xbutton.button &&
|
||||
(!ms->altscrn || (ms->altscrn == (tisaltscr() ? 1 : -1))) &&
|
||||
(match(ms->mod, state) || /* exact or forced */
|
||||
match(ms->mod, state & ~forcemousemod))) {
|
||||
ms->func(&(ms->arg));
|
||||
|
|
@ -860,11 +877,17 @@ xclear(int x1, int y1, int x2, int y2)
|
|||
x1, y1, x2-x1, y2-y1);
|
||||
}
|
||||
|
||||
void
|
||||
xclearwin(void)
|
||||
{
|
||||
xclear(0, 0, win.w, win.h);
|
||||
}
|
||||
|
||||
void
|
||||
xhints(void)
|
||||
{
|
||||
XClassHint class = {opt_name ? opt_name : termname,
|
||||
opt_class ? opt_class : termname};
|
||||
XClassHint class = {opt_name ? opt_name : "st",
|
||||
opt_class ? opt_class : "St"};
|
||||
XWMHints wm = {.flags = InputHint, .input = 1};
|
||||
XSizeHints *sizeh;
|
||||
|
||||
|
|
@ -1139,8 +1162,6 @@ xinit(int cols, int rows)
|
|||
pid_t thispid = getpid();
|
||||
XColor xmousefg, xmousebg;
|
||||
|
||||
if (!(xw.dpy = XOpenDisplay(NULL)))
|
||||
die("can't open display\n");
|
||||
xw.scr = XDefaultScreen(xw.dpy);
|
||||
xw.vis = XDefaultVisual(xw.dpy, xw.scr);
|
||||
|
||||
|
|
@ -1573,29 +1594,44 @@ xdrawcursor(int cx, int cy, Glyph g, int ox, int oy, Glyph og)
|
|||
/* draw the new one */
|
||||
if (IS_SET(MODE_FOCUSED)) {
|
||||
switch (win.cursor) {
|
||||
case 7: /* st extension */
|
||||
g.u = 0x2603; /* snowman (U+2603) */
|
||||
default:
|
||||
case 0: /* blinking block */
|
||||
case 1: /* blinking block (default) */
|
||||
if (IS_SET(MODE_BLINK))
|
||||
break;
|
||||
/* FALLTHROUGH */
|
||||
case 0: /* Blinking Block */
|
||||
case 1: /* Blinking Block (Default) */
|
||||
case 2: /* Steady Block */
|
||||
case 2: /* steady block */
|
||||
xdrawglyph(g, cx, cy);
|
||||
break;
|
||||
case 3: /* Blinking Underline */
|
||||
case 4: /* Steady Underline */
|
||||
case 3: /* blinking underline */
|
||||
if (IS_SET(MODE_BLINK))
|
||||
break;
|
||||
/* FALLTHROUGH */
|
||||
case 4: /* steady underline */
|
||||
XftDrawRect(xw.draw, &drawcol,
|
||||
win.hborderpx + cx * win.cw,
|
||||
win.vborderpx + (cy + 1) * win.ch - \
|
||||
cursorthickness,
|
||||
win.cw, cursorthickness);
|
||||
break;
|
||||
case 5: /* Blinking bar */
|
||||
case 6: /* Steady bar */
|
||||
case 5: /* blinking bar */
|
||||
if (IS_SET(MODE_BLINK))
|
||||
break;
|
||||
/* FALLTHROUGH */
|
||||
case 6: /* steady bar */
|
||||
XftDrawRect(xw.draw, &drawcol,
|
||||
win.hborderpx + cx * win.cw,
|
||||
win.vborderpx + cy * win.ch,
|
||||
cursorthickness, win.ch);
|
||||
break;
|
||||
case 7: /* blinking st cursor */
|
||||
if (IS_SET(MODE_BLINK))
|
||||
break;
|
||||
/* FALLTHROUGH */
|
||||
case 8: /* steady st cursor */
|
||||
g.u = stcursor;
|
||||
xdrawglyph(g, cx, cy);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
XftDrawRect(xw.draw, &drawcol,
|
||||
|
|
@ -1752,9 +1788,12 @@ xsetmode(int set, unsigned int flags)
|
|||
int
|
||||
xsetcursor(int cursor)
|
||||
{
|
||||
if (!BETWEEN(cursor, 0, 7)) /* 7: st extension */
|
||||
if (!BETWEEN(cursor, 0, 8)) /* 7-8: st extensions */
|
||||
return 1;
|
||||
win.cursor = cursor;
|
||||
cursorblinks = win.cursor == 0 || win.cursor == 1 ||
|
||||
win.cursor == 3 || win.cursor == 5 ||
|
||||
win.cursor == 7;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -2001,6 +2040,10 @@ run(void)
|
|||
if (FD_ISSET(ttyfd, &rfd) || xev) {
|
||||
if (!drawing) {
|
||||
trigger = now;
|
||||
if (IS_SET(MODE_BLINK)) {
|
||||
win.mode ^= MODE_BLINK;
|
||||
}
|
||||
lastblink = now;
|
||||
drawing = 1;
|
||||
}
|
||||
timeout = (maxlatency - TIMEDIFF(now, trigger)) \
|
||||
|
|
@ -2011,7 +2054,7 @@ run(void)
|
|||
|
||||
/* idle detected or maxlatency exhausted -> draw */
|
||||
timeout = -1;
|
||||
if (blinktimeout && tattrset(ATTR_BLINK)) {
|
||||
if (blinktimeout && (cursorblinks || tattrset(ATTR_BLINK))) {
|
||||
timeout = blinktimeout - TIMEDIFF(now, lastblink);
|
||||
if (timeout <= 0) {
|
||||
if (-timeout > blinktimeout) /* start visible */
|
||||
|
|
@ -2029,6 +2072,59 @@ run(void)
|
|||
}
|
||||
}
|
||||
|
||||
int
|
||||
resource_load(XrmDatabase db, char *name, enum resource_type rtype, void *dst)
|
||||
{
|
||||
char **sdst = dst;
|
||||
int *idst = dst;
|
||||
float *fdst = dst;
|
||||
|
||||
char fullname[256];
|
||||
char fullclass[256];
|
||||
char *type;
|
||||
XrmValue ret;
|
||||
|
||||
snprintf(fullname, sizeof(fullname), "%s.%s",
|
||||
opt_name ? opt_name : "st", name);
|
||||
snprintf(fullclass, sizeof(fullclass), "%s.%s",
|
||||
opt_class ? opt_class : "St", name);
|
||||
fullname[sizeof(fullname) - 1] = fullclass[sizeof(fullclass) - 1] = '\0';
|
||||
|
||||
XrmGetResource(db, fullname, fullclass, &type, &ret);
|
||||
if (ret.addr == NULL || strncmp("String", type, 64))
|
||||
return 1;
|
||||
|
||||
switch (rtype) {
|
||||
case STRING:
|
||||
*sdst = ret.addr;
|
||||
break;
|
||||
case INTEGER:
|
||||
*idst = strtoul(ret.addr, NULL, 10);
|
||||
break;
|
||||
case FLOAT:
|
||||
*fdst = strtof(ret.addr, NULL);
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
config_init(void)
|
||||
{
|
||||
char *resm;
|
||||
XrmDatabase db;
|
||||
ResourcePref *p;
|
||||
|
||||
XrmInitialize();
|
||||
resm = XResourceManagerString(xw.dpy);
|
||||
if (!resm)
|
||||
return;
|
||||
|
||||
db = XrmGetStringDatabase(resm);
|
||||
for (p = resources; p < resources + LEN(resources); p++)
|
||||
resource_load(db, p->name, p->type, p->dst);
|
||||
}
|
||||
|
||||
void
|
||||
usage(void)
|
||||
{
|
||||
|
|
@ -2047,7 +2143,7 @@ main(int argc, char *argv[])
|
|||
{
|
||||
xw.l = xw.t = 0;
|
||||
xw.isfixed = False;
|
||||
xsetcursor(cursorshape);
|
||||
xsetcursor(cursorstyle);
|
||||
|
||||
ARGBEGIN {
|
||||
case 'a':
|
||||
|
|
@ -2102,6 +2198,11 @@ run:
|
|||
|
||||
setlocale(LC_CTYPE, "");
|
||||
XSetLocaleModifiers("");
|
||||
|
||||
if(!(xw.dpy = XOpenDisplay(NULL)))
|
||||
die("Can't open display\n");
|
||||
|
||||
config_init();
|
||||
cols = MAX(cols, 1);
|
||||
rows = MAX(rows, 1);
|
||||
tnew(cols, rows);
|
||||
|
|
|
|||
Loading…
Reference in New Issue